DataviewJS Snippet Showcase

Considering that daily notes name has the format 2021-11-23, the following snippet lists tasks from previous daily notes and future 3 days, excluding the current day.

let pages = dv.pages('"Daily note"');

dv.taskList(
	pages
	.where(p => (dv.date(p.file.name) <= dv.date(dv.current().file.name) + dv.duration('3 days')) && !dv.equal(dv.date(p.file.name),dv.date(dv.current().file.name)))
	.sort(p => p.file.name, 'asc')
	.file
	.tasks
	.where(t => !t.completed))

I created three sets of task queries for using in Daily/Weekly/Monthly Notes. In the following examples, Daily Note, Weekly Note and Month Note have the formats 2021-01-01, 2021-W1 and 2021-11, respectively, and they can be managed by using the Periodic Notes plugin: liamcain/obsidian-periodic-notes: Create/manage your daily, weekly, and monthly notes in Obsidian.

For instance, the three sets of queries can be inserted into template Daily/Weekly/Monthly Notes in the following way:

  • In the Daily Note template, one can use the query for Daily, Weekly and Monthly Note tasks.
  • In the Weekly Note template, one can use the query for Weekly and Monthly Note tasks.
  • In the Monthly Note template, one can use the query for Monthly Note tasks.

Daily Note tasks:

==Due before and on = date({{date:YYYY-MM-DD}}), and Due in 3 days:==

let pages = dv.pages('"Daily note"');

dv.taskList(
	pages
	.where(p => (dv.date(p.file.name) <= dv.date(dv.current().file.name) + dv.duration('3 days')) && !dv.equal(dv.date(p.file.name),dv.date(dv.current().file.name)))
	.sort(p => p.file.name, 'desc')
	.file
	.tasks
	.where(t => !t.completed))

Weekly Note tasks:

==Due before and in Week = date({{date:YYYY-MM-DD}}).weekyear, and Due in Week = date({{date:YYYY-MM-DD}}).weekyear + 1:==

let pages = dv.pages('"Weekly note"');
let dateToday = dv.date('{{date:YYYY-MM-DD}}');

dv.taskList(
	pages
	.where(p => (p.file.name <= dateToday.year.toString() + '-W' + (dateToday.weekNumber + 1).toString()))
	.sort(p => p.file.name, 'desc')
	.file
	.tasks
	.where(t => !t.completed))

Monthly Note tasks:

==Due before and in Month = date({{date:YYYY-MM-DD}}).month, and Due in Month = date({{date:YYYY-MM-DD}}).month + 1:==

let pages = dv.pages('"Monthly note"');
let dateToday = dv.date('{{date:YYYY-MM-DD}}');

dv.taskList(
	pages
	.where(p => (p.file.name <= dateToday.year.toString() + '-' + (dateToday.month + 1).toString()))
	.sort(p => p.file.name, 'desc')
	.file
	.tasks
	.where(t => !t.completed))
2 Likes

Sure !
The first line is the header, like Paper, Title, Year etc…
All my files are in the folder Zettelkasten.

The line "[[" + b.file.name + "|" + (b.file.aliases[1] || b.file.aliases[0]) + "]]", means to create a link for the first column, you can skip it.
The lines

b.file.aliases[0],
b.Year,
b.completion_reading,
b.completion_note,

are the informations I have added in the header of the files, like this

image

Here is what my header looks like.

2 Likes

Howdy again @dryice ! Sorry for the delay - holidays and all.

Let’s see if I can help! I’ll paste the first code block below, but first, a disclaimer - you should never, EVER, blindly paste code into dataviewjs if you don’t understand it. Bad actors could utilize it to wreak havoc on your system. This isn’t that but good practice moving forward :slight_smile:

Now, the full code block:

const {update} = this.app.plugins.plugins["metaedit"].api;
const buttonMaker = (pn, pv, fpath) => {
    const btn = this.container.createEl('button', {"text": "Finished!"});
    const file = this.app.vault.getAbstractFileByPath(fpath)
    btn.addEventListener('click', async (evt) => {
        evt.preventDefault();
        await update(pn, pv, file);
		await update('completed-date',DateTime.local().toISODate(),file);
    });
    return btn;
}

let taskList = dv.pages("[[" + dv.current().file.name + "]]")
	.filter(p => p.tags == "tasks")
	.filter(p => p.status == "In Progress");
	
dv.table(["Task","Priority","Due Date","Pending Subtasks","Completed Subtasks"],
	taskList.sort(t => t.priority)
	.map(t => [t.file.link,
		t.priority,
		t["due-date"],
		t.file.tasks.filter(t => !t.fullyCompleted).length,
		t.file.tasks.filter(t => t.fullyCompleted).length,
		buttonMaker('status','Finished',t.file.path)
		])
)

To answer your questions directly:

  1. You might want to read the MetaEdit docs to understand a little more thoroughly, but the ‘FIELD’ is the DataView/YAML field that you want to update (for instance, ‘completion-date’ is a YAML field on my Task notes.

  2. Hopefully the code block above helps, but if it doesn’t, please let me know! I’m not sure I quite understand the issue you might be having here.

Does anyone have an example of the YAML frontmatter for the “people” entries? I am struggling to get the code to work so this would be very helpful.

Hello, all.

Is there anyone who know how to embed the results from dataviewjs?

```dataviewjs
let pages = dv.pages("#math").where(b => b.difficulty >= 1);
for (let group of pages.groupBy(b => b.material)) {
   dv.header(group.key);
   dv.list(group.rows.file.link);
}
Now, I got the list of links to the files.

file1
file2
file3

What I want to get is like these

![[file1]]
![[file2]]
![[file3]]

Thnak you in advance.
1 Like

I’m struggling to figure out how to embed the results from dataviewjs.

With the following script,

dv.paragraph("[[ABC]]")

I got the link to ABC.md in preview.

But, with the following script to embed ABC.md

dv.paragraph("![[ABC]]")

there is only ABC without the exclamation mark and any link.

At first, it embeds ABC.md successfully.
But, after a few seconds, it disappers leaving only ABC.

Can anyone help me solve this problem?

1 Like

i happened on a related question on the obsidian discord this afternoon. This will do what you want, I think:

(enclose this in a set of three tick marks in Obsidian)
dataviewjs
dv.paragraph(dv.fileLink("ABC",1))

I think you should leave the ‘paragraph’ attribute and use a more generic ‘div’ attribute to ensure it runs smoothly independently of your theme:

dv.el("div", dv.fileLink("MRCK",1))

Within a dataviewjs code block

1 Like

I made a snippet to track my daily habits along with a streak and total count.

To make this work, each daily journal entry needs frontmatter that looks like this:

---
habits:
  habit_1:
  habit_2:
  habit_3:
---

To use this frontmatter everyday, you can enable the Templates core plugin in Settings > Core plugins > Templates.

Then go to the options in Settings > Plugin options > Templates, and choose your folder location. In that folder, create a file called Daily_note where you will add the above frontmatter.
Then in Settings > Plugin options > Daily notes, update your Template File Location to the above your_template_folder/Daily_note.md. Now whenever you create a daily note, it will contain that frontmatter.

To see the table view of all your habits like in the first image, you can copy this snippet. You need to get the raw snippet, so if you’re not familiar with how that works, just use this link

In that snippet, the first section tells you what you need to change in order to match your system. Most important, habit_names have to match the exact names of the habits in your frontmatter. And daily_journal_loc needs to point to the folder where your journals are located.

Hope this helps.

8 Likes

I came to the forum because i’ve been hitting this issue as well.

I have an image IMG_20220107_230609.jpg

I have tried

dv.el("div", "![[IMG_20220107_230609.jpg]]")
dv.el("div", "![[IMG_20220107_230609.jpg|200]]")
dv.el("div", dv.fileLink("IMG_20220107_230609.jpg", true))
dv.el("div", dv.fileLink("IMG_20220107_230609.jpg", true, "200"))
dv.paragraph("![[IMG_20220107_230609.jpg]]")
dv.paragraph("![[IMG_20220107_230609.jpg|200]]")
dv.paragraph(dv.fileLink("IMG_20220107_230609.jpg", true))
dv.paragraph(dv.fileLink("IMG_20220107_230609.jpg", true, "200"))

Appears for a few seconds and then disappears again. I’m wondering whether there’s a bug. I had a look through the forum and noticed this thread that raised there was an issue with the Obsidian Plugin API not rendering embeddings… could this be the issue?

I wondered whether maybe the image size was an issue so I tried reducing the image size with the 200

Update:

Seems there’s an issue raised on the dataview plugin here related to the rendering of embeddings.

And rendering of embeddings in plugins is a recent addition. So maybe there’s some updates or fixes needed.

Can someone help with this ‘Birthday’ issue please. It used to render the age in whole years of a person on their next birthday, along with their birthDate. Recently however, the age began rendering up to 14 decimal points – odd.

```dataview
TABLE birthDate as "DoB", choice(
date(today).month * 100+date(today).day = birthDate.month * 100+birthDate.day,(date(today)-birthDate).year,(date(today)-birthDate).year+1) as Age
FROM "People"
WHERE file.name != this.file.name and birthDate != NULL AND !deathDate and 
choice(date(today).month * 100+date(today).day > birthDate.month * 100+birthDate.day,
(date(today).year+1) * 10000 + birthDate.month * 100 + birthDate.day,
date(today).year * 10000 + birthDate.month * 100 + birthDate.day) <= (date(today) + dur(28 days)).year * 10000+(date(today) + dur(28 days)).month * 100+(date(today) + dur(28 days)).day
SORT choice(
date(today).month * 100+date(today).day > birthDate.month * 100+birthDate.day,
(date(today).year+1) * 10000 + birthDate.month * 100 + birthDate.day,
date(today).year * 10000 + birthDate.month * 100 + birthDate.day)
![image|690x436](upload://jQ0c3YoGLq3sPzu2XmPEJAQrE1i.png)

Beautiful!
Can you share the specifics of the notes that are being referenced? I’m not familiar enough with JS to decipher what it’s referencing.

Do they need specific tags or path to work?

1 Like

Hi,
I am new to Obsidian and I really find dataview to be very helpful. Even more so with js added to it. I am however not the strongest coder so I run into a bit of an issue.
What I want to achieve is a list of all my tasks on all pages sorted by the first tag in each task. All my tasks starts with a tag.
So I started with listing all not completed task.

dv.taskList(dv.pages().file.tasks.where(t => !t.completed));

Part two is a bit more tricky, I have found.
I have managed to make it a single list(without headings) but I think that it is due to either a bug or something I dont understand. And it is not sorted by the tag.

This is the code for that(dataview obviously):
TASK WHERE !completed GROUP BY file.tag

If i add an “s”(file.tags) to the last part of this query it will list all tasks in same file with Tags as heading.

Anyone got any ideas?

Thanks

Tags in task text aren’t parsed as tags. They’re just content (obsidian-tasks understands tags in the context of tasks, but dataview does not and Obsidian does not). The tags you see in the latter example are the file’s tags, not the tags attached to the task. Since the tag is at the beginning of the text, what you actually want is to sort alphabetically. You can accomplish that with this:

dv.taskList(dv.pages().file.tasks
    .where(t => !t.completed).sort(t => t.text, "asc"))

To get all tasks in one list, you have to turn off the grouping behavior, which is done inside the dv.taskList() call:

dv.taskList(dv.pages().file.tasks
    .where(t => !t.completed).sort(t => t.text, "asc"), false)
2 Likes

This was perfect, Thank you! Thanks also for the explanaition. :slight_smile:
I am trying to get into javascript and dataview to see what else I can do.

1 Like

Hello.

In the past I used an exemplar created by someone online to log my takeaway food entries in the YAML of my daily notes.

---
date: 2012-09-19
purchases:
  - store: "[[some store]]"
    item: some item
    comments: comments
  - store: "[[another store]]"
    item: another item
    comments: other comments
---
---
date: 2012-09-21
purchases:
  - store: "[[another store]]"
    item: potatoes, potatoes
  - store: "[[another store]]"
    item: a very big watermelon
---
---
date: 2012-09-20
purchases:
  - store: "[[some store]]"
    item: apples
  - store: "[[some store]]"
    item: oranges
---
// 1. Let's gather all relevant pages

const pages =
  dv.pages('"_tmp/20210922 test for sumant28/Life"')
    .filter(page => page.file.name.includes("test note"));

// 2. Now let's transform from thing per date (we have single page for each date) into thing per purchase (we want to have as many rows in a table as all purchases extracted from all pages)

const purchases = [];

pages.forEach(page => {
  page.purchases.forEach(purchase => {
    purchases.push({
      file: page.file,
      date: page.date,
      store: purchase.store,
      item: purchase.item,
      comments: purchase.comments,
    });
  });
});

// 3. Let's sort it by date, newest first (note "-" before "purchase.date")

purchases.sort(purchase => -purchase.date);

// 4. And let's print a table of those purchases

dv.table(
  [
    "File",
    "store",
    "item",
  ],
  purchases.map(purchase => [
    purchase.file.link,
    purchase.store,
    purchase.item,
  ])
 );

I had logged dozens of entries making the resulting table too unwieldy. I already have pages set up for each store in Obsidian which is a file link in the table using this syntax “[[store]]”. I want to display a filtered DataviewJS with purchases only from that store that goes on the bottom of every store file in my vault. I figured out how to filter the table using an extra int field called rating but I want to filter instead based on the .includes function but whenever I try to do this I get the error message saying purchases.store.includes is not a function.

1 Like

So, just to clarify. Each week you go into the dataview table and fill in the var start and var end dates manually correct?

On each of my daily pages I have a link to the weekly page that it belongs in. Is there a way to use weekly link to pull the corresponding daily pages? That would make it more automated for me.

Also, is there a way to add a progress bar into a dataviewJS table? I have a book reading progress bar formatted like this

("![progress + " + (round((Percent_Read/100)*100)) + " %](https://progress-bar.dev/" +(round((Percent_Read/100)*100)) + “/)”) AS Progress__

in my dataview table it works, is there a way to add this to a dataviewjs table?

Hi dataviewjs community,

I am just exploring the possibility to send a note as a email. I am just using a simple URL scheme to generate the connection btw Obsidian and my mail app. subject is generated smoothly in the block below, and i could generate recipients (through a user prompt) easily.
The tricky bit is the email body and more specifically:

  1. The call method for the note content (i am trying dv.io.load which works but embarks metadata & everything). Is there a slicker way to call the note’s content?
  2. URL encode the note’s content. Is there a quick way to do so or is it a series of .replace()?

Many thanks in advance for any help

M

let content = await dv.io.load(dv.pages("Note").file.path);
let subject = (dv.current().Alias[0] === 'undefined') ? dv.current().file.name.replace(" ", "%20") : dv.current().Alias[0].replace(" ", "%20");
dv.el("center", '[Send as email](readdle-spark://compose?body=' + content.replace(" ", "%20") + '&subject=' + subject + ')')
1 Like