Help creating a very simple habit tracker

What I’m trying to do

I’m trying to create a very simple habit tracker based on a habits note which is updated by daily notes. I want each daily note to have checkboxes for each habit, and when I click these checkboxes, the habit tracker should update. I know there are habit tracker plugins available, but I want to keep it simple and I like the format I have set up now (or at least I will when it starts working!).

Things I have tried

I’ve come up with the following code which has a problem described below.

My dataview code is as follows:

TABLE WITHOUT ID  
file.link AS Date,  
choice(contains(list.text, "[x] Sleep"), "🟩", "🟥") AS "🛌",
choice(any(contains(list.text, "[x] Exercise")), "🟩", "🟥") as "🏃",
choice(contains(list.text, "[x] Reading"), "🟩", "🟥") as "📚", 
choice(any(contains(list.text, "[x] Meditation")), "🟩", "🟥") as "🧘",  
choice(any(contains(list.text, "[x] Writing")), "🟩", "🟥") as "✍️" 
FROM #dailies  
WHERE file.day <= date(now) AND file.day >= date(now) - dur(7days)  
SORT file.day ASC  

And I have a template so that each daily note has the following format where the top header is in YAML:


Properties
tags: #dailies
date: {{date}}

{{date}}

Habits

  • Sleep
  • Exercise
  • Reading
  • Meditation
  • Writing

PROBLEM

When I create a daily note, this shows up in my dataview table but when I check the boxes, my dataview table does not update. All of the boxes stay red. Can someone please provide me with the correct dataview code? I’d really like to make this work. (And take it easy on me I’m clearly a beginner :slight_smile: ). (Ps I’ve done a bit of research and I really cannot for the life of me figure out how to use contains/anything with dataview in this way).

There are two major issues with your query:

  • The text of list items of a file is stored within file.lists.text, not just list.text
  • And you should probably look at file.tasks.text also, but in either case these do not show the completed state of the tasks

So your logic is kind of correct, but you’re looking into something not having any values, so then it’ll never be correct…

Let us do stuff in a slightly different order with this query:

```dataview
TABLE WITHOUT ID file.link AS Date, habits, 
  choice(contains(habits, "Sleep"), "🟩", "🟥") AS "🛌",
  choice(contains(habits, "Exercise"), "🟩", "🟥") AS "🏃",
  choice(contains(habits, "Reading"), "🟩", "🟥") AS "📚",
  choice(contains(habits, "Meditation"), "🟩", "🟥") AS "🧘",
  choice(contains(habits, "Writing"), "🟩", "🟥") AS "✍️"
FROM #dailies
WHERE file.day <= date(now) AND file.day >= date(now) - dur(7days)
FLATTEN list(map(file.tasks, (t) => choice(t.completed, t.text, ""))) as habits
SORT file.day ASC
```

The central point of this query is the mapping of the completion of tasks done in the line starting with FLATTEN:

  • FLATTEN list( ... ) as habits – After evaluating ... we store that result as a list into the variable habits
  • map(file.tasks, (t) => ... ) – Loop through the tasks of the current file, and let each task be presented to ... as t
  • choice(t.completed, t.text, "") – Using choice() we check whether the task is t.completed, and if so, we map the result to the t.text of the task

All in all this would provide a list of the completed habits stored into habits. And then we can present the result in our table if we can locate our habit in the completed habit list.

PS! I kept the display of the list habits in this query (at the first line), just to show what it looks like in the different cases, but you can of course remove this column when you see what’s happening.

This is amazing thank you!!