DataviewJS Snippet Showcase

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.

2 Likes

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

The link doesn’t work (404).
Can you repost it?

Hi, Can someone please help me do a custom sorting with a comparator (I want to sort by type then by date then by state then by file.ctime) ?
I’m new to this, so the docs didn’t help me much.

So, I was heavily inspired to make my own book list, that also accounts for books I have yet to read and books I am reading.


This is what it looks like, but the code is ‘messy’, if anyone has thoughts on cleaning it up it would be appreciated.

```dataviewjs
const {
    update
} = this.app.plugins.plugins["metaedit"].api
const buttonMaker = (pn, pv, fpath, text) => {
    const btn = this.container.createEl('button', {
        "text": text,
        "class": "button-55"
    });
    const file = this.app.vault.getAbstractFileByPath(fpath)
    btn.addEventListener('click', async (evt) => {
        evt.preventDefault();
        await update(pn, pv, file);
    });
    return btn;
}
const {
    createButton
} = app.plugins.plugins["buttons"]


for (let group of dv.pages("#book").where(p => p["time-read"] == null && moment(luxon.DateTime.now().toISODate()).diff(moment(p["release-date"])) < 0).groupBy(p => p.Started == null ? "Not Started" : "Currently Reading")) {
    dv.header(4, group.key + ": " + group.rows.length);
    dv.table(["Title", "Author", "Series", "Started On", " "],
        group.rows.sort(k => k.Started, 'desc').map(k => ["[[" + k.file.path + "|" + k["Title"] + "]]", k["Author"], k["Series"] ? k["Series"] + ", " + k["number-in-series"] : "N/A", k["Started"] ? k["Started"] : "Untouched", k["Started"] && k["pageprogress"] / k["pagecount"] < 1 ? "<progress value=" + k["pageprogress"] / k["pagecount"] + " max=1></progress>" :
            createButton({
                app,
                el: this.container,
                args: {
                    name: k["Started"] ? "Completed" : "Begin"
                },
                clickOverride: {
                    click: update,
                    params: [k["Started"] ? "time-read" : "Started", luxon.DateTime.now().toISODate(), k.file.path]
                }
            })
        ]))
}

type or paste code here

8 Likes

This looks great and is essentially what I have been trying to create with very little knowledge. Thank you. Would you mind showing us what your book note looks like? And what time-read and date-published mean? Also, when I used the formula, my currently-reading is on the bottom instead of the top.

Hi, I’m trying to do a similar thing with Dataview: re-formatting a date in a table.

I’d like to use a frontmatter date called created on my notes which uses the format dddd, MMMM Do YYYY, hh:mm AA, but display it in a table in the format MM.dd and sort the table ascending by these dates.

Can anyone provide any tips for a snippet for this? Thanks!

Here’s one thing you can do to clean it up a bit. Instead of “[[” + k.file.path + “|” + k[“Title”] + “]]”, you can just use k.file.link,.

Also if you want to add a cover you can put cover: in your YAML and then use the following in the dataview table.

group.rows.sort(k => k.Started, ‘desc’).map(k => ["![Cover|90](" + k.cover + “)”, k.file.link, k[“Author”], k[“Series”] ? k[“Series”] + “, " + k[“series-number”] : “N/A”, k[“Started”] ? k[“Started”] : “Untouched”, k[“Started”] && k[“pageprogress”] / k[“pagecount”] < 1 ? “<progress value=” + k[“pageprogress”] / k[“pagecount”] + " max=1>” :

Do I need to change the date format in the code to my own (DD-MM-YYYY as set in Daily Notes) ?

I don’t seem to get it working, I get the hint between () and have named the notes with today’s date in the aforementioned format, but I get no navigation.

Hi, is it possible to create a Templater ‘suggester’ using DataviewJS?

I’d like to be able to generate a Templater select list (suggester) from a list of files in a folder.

I’ve seen some use of Dataview ‘embedded’ in other scripts, but I’m familiar enough to make this work.

Thanks

1 Like

Hi,

Unless this is already possible in DataviewJS, please find in this forum as well as in Dataview’s github a FR for embedding local media (audio, image and video) in a dataview query (table, list, etc…), possibly using relative paths inside vault for better cross-platform portability.

Thanks !

I was using k.file.link, But wanted to include titles that weren’t acceptable as file names.

---
abandoned: null
release date: 1970-01-01
pageprogress: null
pagecount: null
Author: Becky Chambers
Title: A Closed and Common Orbit
Series: Wayfarers
number-in-series: 2
time-read: 2020-08-20
Mood: 😭😭🥰😭
tags: book
---

This is what my book notes look like. time-read is the date I finished the book. date-published/release date is essentially what it sounds like. There are a lot of books coming out this year that I want to read, and I don’t want them to get buried, so I thought it would be good to keep it organised.

Not quite sure why your currently reading is at the bottom. But if you have more books in that than in your unreads, that might have something to do with it.