# DataviewJS Snippet Showcase

**URL:** <https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847>\
**Category:** Workflows & Templates\
**Tags:** dataview\
**Created:** [May 8, 2021, 8:02am UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847 "2021-05-08T08:02:55Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Moonbase59](https://forum.obsidian.md/user_avatar/forum.obsidian.md/moonbase59/32/13648_2.png) [@Moonbase59](https://forum.obsidian.md/u/Moonbase59)\
**Post date:** [May 8, 2021, 8:02am UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/1 "2021-05-08T08:02:55Z")

</div>

_Dataview_ plugin versions 0.3.0+ offer enhanced, _javascript-enabled_ `dataviewjs` code blocks. @blacksmithgu is constantly adding features and functions to it.

Since the [Dataview plugin snippet showcase](https://forum.obsidian.md/t/dataview-plugin-snippet-showcase/13673) is getting _huge_, I thought we start a new—_Dataview **JS** _-only— snippet showcase here.

## With great power comes great responsibility …

_DataviewJS_ has a steeper learning curve and is not for the faint of heart—you do have full Javascript access but must adhere to the rules, or you’ll debug forever and get real frustrated. But it’s _worth_ it. 🙂

_If you’re unsure, start out with the “normal” `dataview` codeblocks and syntax._

## … and endless new possibilities!

Almost everything you ever wanted can now be done.

If not, …

- [open an issue on GitHub](https://github.com/blacksmithgu/obsidian-dataview/issues) _(please check for similar issues before posting!)_,
- always _test with the latest version_, and
- [read the docs!](https://blacksmithgu.github.io/obsidian-dataview/docs/intro)

## Sharing is progress!

So please …

- _share_ your findings and code snippets with us,
- _help others_, and
- let us know about _your creative new ideas!_

If the forum lets me, I’ll edit this first post from time to time, to include new information.

---

<div class="post-metadata">

**Author:** ![Moonbase59](https://forum.obsidian.md/user_avatar/forum.obsidian.md/moonbase59/32/13648_2.png) [@Moonbase59](https://forum.obsidian.md/u/Moonbase59)\
**Post date:** [May 8, 2021, 9:42am UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/2 "2021-05-08T09:42:18Z")

</div>

## Show family members, friends and places that are _nearby_

I love location data, maps, and visualizing stuff. When I plan to travel or visit a friend or family member, I _love_ to see “what’s near” in each person or location note. Automatically linking places and people together, so to say.

 ![obsidian-dataview-nearby-preview-km](https://forum.obsidian.md/uploads/default/original/2X/c/cd1e190d4115a6935a5429fee51683d41cc34739.png)  
“Nearby” with German setting, in kilometres (text untranslated; check ‘km’ and the decimal _comma_)

- If I visit a friend, I can check if there are other friends or places of interest nearby, and we could maybe visit them together.
- I can check if other friends are near enough to do something together, maybe meet for a barbeque.
- When sightseeing, I won’t miss nearby friends, business contacts, favourite restaurants or other sights anymore.

## Goals

- Never miss anything _nearby_ anymore.
- Have this dataview available as a template so it can be _in every person, business contact, and place-of-interest note_ and automatically show me _what’s near this place_.
- _No more people and location notes without location data_ (easily be copied from Google Maps or the like).

## Requirements

- _All people/location notes_ must have a

```auto
location: [lat, lon]

```

entry in the YAML frontmatter. (This syntax has something to do with YAML & JS data structure and easy parsing. The sequence [lat, lon] has been chosen for practical reasons: People are used to it and it can easily be copied from Google Maps and others.)
- _Dataview 0.3.0+_ installed.
- `moment.js` available (it currently is).
- Distance units of **m** , **km** , **yd** and **mi** must be usable and easy to switch.
- Distances must be calculated as correct straight-line distances, taking into account that Earth is not a perfect sphere but a rotational ellipsoid.
- Distances must also be available as (approximate; for speed and offline use) driving distances.
- Distances shall be shown with the unit appended but internally numeric, for easy calculation/comparison.
- Numbers shall be formatted _according to the language currently set in Obsidian_ (`4,096.1` vs `4.096,1`). The OS’s system setting shall only be used if all else fails.
- Date & time strings must be easily formatable however I wish, defaulting to _ISO-8601_ (`2021-05-08T10:34:05+02:00`).
- Very long note title links shall optionally be shortened in Dataview table views, using my [dataview-shorten-links.css snippet](https://forum.obsidian.md/t/how-to-achieve-css-code-snippets/8474/152).
- Tags (from frontmatter only, a current Dataview restriction) shall be shown in one (comma- or blank-)separated string, _not_ as a list.
- The list shall be sorted by distance from “here” (i.e., this note).
- The distance values shall be clickable and lead to the Google Maps Route Planner, destination already filled in, and start point taken from the current location.
- Above the table, a text line shall show the currently set “nearby” radius as well as the selected unit of measurement (`within 100 km driving distance`, `within 50 mi straight-line distance`), so we later know what’s actually shown in the table.

## Current status

- Proof-of-concept, working but params have to be set in the codeblock (instead of being taken from YAML).
- It is still already usable, and should have no major bugs.

 ![obsidian-dataview-nearby-preview-mi](https://forum.obsidian.md/uploads/default/original/2X/8/83f1804319827f15a3dba51edb2e78f06e99b0a7.png)  
“Nearby” with English setting, in miles (check ‘mi’ and the decimal _point_)

### To-Do

- [x] ~~Wait for new Dataview version that allows reading from “this” note, and other things.~~
- [x] ~~Make unit and radius readable from “this” note, most probably by using something like:~~

```auto
nearby: 50 km

```

~~or~~

```auto
nearby: 50 mi

```

~~which would split the string and use the numeric part as radius, the textual part as the desired unit for calculating & showing in the table.~~
- [x] ~~Read origin (starting point) from “this” note so all can be automatic, even when the location changes.~~
- [x] ~~Possibly make the searchterm for `dv.pages()` available in YAML. Don’t know yet.~~

## Current Code

This is surely the part you’ve been waiting for! 😁

_Note: I might change the code **here** when updating it, so check more often._ It’s easier than to keep a zillion copies down below.

This is the `dataviewjs` code block only. You’ll have to type your own header. 😉

```javascript
// Nearby Family Members, Friends and Places
// 2021-05-15 - Matthias C. Hormann (Moonbase59)

// set parameters (to be supplied via YAML frontmatter, eventually)
// DV 0.3.3 interprets "500000 m" as a Luxon duration,
// so we have to put nearby: '"500000 m"' and remove the ".
let nearby = dv.current().nearby.replace(/['"]+/g, '');
let unit = nearby.split(' ')[1];
let radius = nearby.split(' ')[0];
let origin = dv.current().location;

// search term as used in dv.pages()
// use "#tags" or '"folder/subfolder"' for a folder
let searchterm = dv.current().searchterm;

//======================================================================

function getDistance(origin, destination, unit='m') {
    // return distance in selected unit (m,km,yd,mi)
    var factor = 1.0;
    switch (unit) {
      case 'm':
        factor = 1.0;
        break;
      case 'km':
        factor = 1000.0;
        break;
      case 'yd':
        factor = 0.9144;
        break;
      case 'mi':
        factor = 1609.344;
        break;
      default:
        factor = 1.0;
        console.warn("getDistance: Invalid unit '%s', using 'm'. Valid units are: m,km,yd,mi.",unit);
    }

    var lon1 = toRadian(origin[1]),
        lat1 = toRadian(origin[0]),
        lon2 = toRadian(destination[1]),
        lat2 = toRadian(destination[0]);

    var deltaLat = lat2 - lat1;
    var deltaLon = lon2 - lon1;

    var a = Math.pow(Math.sin(deltaLat/2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(deltaLon/2), 2);
    var c = 2 * Math.asin(Math.sqrt(a));
    var EARTH_RADIUS = 6371000; // 6,371 km in metres
    return c * EARTH_RADIUS / factor;
}

function toRadian(degree) {
    return degree*Math.PI/180;
}

function getDrivingDistance(origin, destination, unit='m') {
    // PREDICTED, using a factor.
    // Much faster, and no need for Internet access.
    // The U.S. predict 1.417, based on statistical analysis.
    // For Germany, I’ve found 1.3 a good value (comparing w/ Google Maps "best route")
    var factor = 1.3;
    return getDistance(origin, destination, unit) * factor;
}

//======================================================================

// Show what we will display.
dv.paragraph("List shows nearby places (within " + radius + " " + unit + " driving distance).");
dv.paragraph("<br><br>");

// get the pages
let pages = dv.pages(searchterm)
  .where(p => p.location &&
    // must be >0 so we don’t catch ourselves!
    getDrivingDistance(origin, p.location, unit) > 0.0 &&
    getDrivingDistance(origin, p.location, unit) <= radius)
  .sort(p => getDistance(origin, p.location, unit));

// create table
dv.table(["Name", "Tags", "Distance*"],
  pages.map(p => [
    // The name
    p.file.link,
    // tags (show '–' if none defined)
    (p.file.etags ? p.file.etags.join(' ') : '–'),
    // straight-line distance
    /*
    getDistance(origin, p.location, unit)
      .toLocaleString(moment.locale(), {maximumFractionDigits: 1}) + " " + unit,
    */
    // predicted driving distance and Google Maps Route Planner Link
    (getDrivingDistance(origin, p.location, unit)
      .toLocaleString(moment.locale(), {maximumFractionDigits: 1}) + " " + unit)
      .link('https://www.google.com/maps/dir/?api=1&dir_action=navigate&destination=' + p.location[0] + ',' + p.location[1]),
  ])
);

// show a small legend
dv.paragraph("<small>* Approximate driving distance; when clicked, opens a new Google Maps Route Planner window.</small>");

```

## Changelog

- **2021-05-08** — Original version.
- **2021-05-15** — Fixed To-Dos, add YAML features:
  - `nearby: <number> <unit>` in YAML frontmatter now allows specifying how near it shall be, and the units to display. Knows **m** , **km** , **mi** and **yd**.
  - `location: [<lat>, <lon>]` in YAML specifies the starting point (i.e. “here”) for distance calculations.
  - `searchterm: …` in YAML is a normal Dataview `from` type search term. Examples:

```auto
searchterm: "#family or #friends or #location"

```

or

```auto
searchterm: '"People"'

```

  - Make tags inline and clickable. _Note:_ Using my [dataview-shorten-links.css snippet](https://forum.obsidian.md/t/how-to-achieve-css-code-snippets/8474/152) will work but display one line per tag. Adapt the CSS to select `a.internal-link` only, or _not_ to select `a.tag` if you want more than one tag per line.
  - Code above updated .

## Questions, Help

1. If anyone knows how I can optimize the overuse of `getDistance()` and `getDrivingDistance()`, _please let me know!_

2. What’s the performace/memory hit creating a new `pages` variable? I mainly did it to decouple, not creating even longer spaghetti code. Or should I string it all together and _not_ use an extra variable?

3. If anyone knows about an easy (and _working!_) way to get at “this” notes YAML frontmatter _inside_ the code block, let me know.

4. Is it possible to `![[nearby]]` _embed_ this within other notes and have it read its YAML frontmatter _from the including parent?_ Because that would be truly dynamic—only keep it in _one_ place and just include it! Would save the hassle of changing it in hundreds of existing people/location notes, eventually!

## Have fun & Keep ’em coming!

---

<div class="post-metadata">

**Author:** ![Moonbase59](https://forum.obsidian.md/user_avatar/forum.obsidian.md/moonbase59/32/13648_2.png) [@Moonbase59](https://forum.obsidian.md/u/Moonbase59)\
**Post date:** [May 8, 2021, 11:31am UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/3 "2021-05-08T11:31:40Z")

</div>

So _Dataview 0.3.3_ is here and we got `dv.current()`. Im just testing reading data from YAML frontmatter instead of hardcoding it into the codeblock.

**Caveat:** Dataview seems to pre-interpret the YAML, and so my entry

```auto
nearby: 500000 m

```

is “interpreted” as a Luxon duration of 500,000 _minutes_! Which means, I can’t access the string `500000 m` and work on it in my function. (It’s meant to mean “500,000 metres”.) Argh.

See also: [0.3.3: Interprets YAML frontmatter string as Luxon Duration! Argh! · Issue #189 · blacksmithgu/obsidian-dataview · GitHub](https://github.com/blacksmithgu/obsidian-dataview/issues/189)

Hope our friend will come up with a good fix.

---

<div class="post-metadata">

**Author:** ![Rishi](https://forum.obsidian.md/user_avatar/forum.obsidian.md/rishi/32/398_2.png) [@Rishi](https://forum.obsidian.md/u/Rishi)\
**Post date:** [May 8, 2021, 4:19pm UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/4 "2021-05-08T16:19:31Z")

</div>

This is a lot of amazing work. Although, I am not going to use something like this myself, I still think it is gold!

P.S. Good thought on updating the code as opposed to adding newer ones below. We should make that a movement and make things on the forum simpler!

---

<div class="post-metadata">

**Author:** ![davecan](https://forum.obsidian.md/letter_avatar_proxy/v4/letter/d/3da27b/32.png) [@davecan](https://forum.obsidian.md/u/davecan)\
**Post date:** [May 8, 2021, 9:59pm UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/5 "2021-05-08T21:59:39Z")

</div>

> [@Moonbase59](#):
>
> Is it possible to `![[nearby]]` _embed_ this within other notes and have it read its YAML frontmatter _from the including parent?_ Because that would be truly dynamic—only keep it in _one_ place and just include it! Would save the hassle of changing it in hundreds of existing people/location notes, eventually!

I submitted a feature request a few weeks ago to add stored queries and the dev agreed it would be a useful add-on. Hopefully its coming soon because I have the same problem.

My recommendation was along the lines of creating a folder where each query is defined in a separate file and then including them with syntax like this:

```auto

```

An implementation in the JS API would presumably look something like:

```dataviewjs
dv.include('file_path', [key_val_pairs])

```

Using `dv.current()` seems to be a move towards supporting this type of feature.

---

<div class="post-metadata">

**Author:** ![Moonbase59](https://forum.obsidian.md/user_avatar/forum.obsidian.md/moonbase59/32/13648_2.png) [@Moonbase59](https://forum.obsidian.md/u/Moonbase59)\
**Post date:** [May 9, 2021, 7:13pm UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/6 "2021-05-09T19:13:46Z")

</div>

## Upcoming Birthdays (robust & flexible)

Here’s a rather robust and flexible list of upcoming birthdays that

- shows **link** , **next birthday** , and **age** someone will turn to
- has a configurabe **date range** (from today, for a “natural language” duration)
- sorts by **next birthday**
- uses **locale settings** from the language _Obsidian is set to_
- doesn’t choke when crossing the year boundary
- has YAML **searchterm** configuration
- has YAML “natural language” **duration** configuration; “odd” data like `duration: 0.5 years` will be auto-translated to `6 months` (or `6 Monate` in German)
- has YAML **date format** configuration (yay!)
- has a configurable **info line** above the table (can be disabled)

 ![obsidian-dataview-upcoming-birthdays](https://forum.obsidian.md/uploads/default/original/2X/4/4f70d33649d6c45a7ac9c86b3226b0cb3f021dc0.png)  
Upcoming birthdays with English settings, custom date format and info line

**The technically-minded** may also find interesting:

- utility functions that can be used for table data
- custom function for “where”
- comparator function for “sort”
- easily translatable “info line” with parameters
- how I need to _undo_ Dataview’s YAML pre-parsing of dates and durations

 ![obsidian-dataview-upcoming-birthdays-de](https://forum.obsidian.md/uploads/default/original/2X/5/5d6ccde0ae290500f38c930b2c91142f45f27304.png)  
Upcoming birthdays with German settings, custom date format and info line

## Requirements

- _Dataview 0.3.3+_
- `moment.js` (comes with Obsidian)
- Notes to be included must have a birthday as `YYYY-MM-DD` in the frontmatter:

```auto
birthday: 1959-07-19

```

- The note _using_ this script **must** have the parameters `searchterm` and a (more or less) “natural language” `duration` in the frontmatter:

```auto
#searchterm: "#family or #friends"
searchterm: '"People"'
duration: 1 year

```

- The note using this script **_can_** have an additional `dateformat` in the frontmatter:

```auto
dateformat: "ddd, D MMMM YYYY"

```

If left out or empty, it will default to `YYYY-MM-DD`.

## Code

### YAML frontmatter example

```auto
#searchterm: "#family or #friends"
searchterm: '"People"'
duration: 1 year
dateformat: "ddd, D MMMM YYYY"

```

### `dataviewjs` code

This contains some utility functions that can be used in your table, like `nextBirthday()`, `turns()`.

```javascript

var start = moment().startOf('day');
var end = moment(start).add(dv.current().duration);
var dateformat = "YYYY-MM-DD";
if (dv.current().dateformat) { dateformat = dv.current().dateformat; }

// info text above table, {0}=duration, {1}=start date, {2}=end date
// parameters can be left out, or the string empty
var infotext = "Upcoming birthdays for {0} from now ({1} – {2})<br><br>";

//======================================================================

function nextBirthday(birthday) {
    // Get person’s next birthday on or after "start"
    // returns a moment
    
    // need to "unparse" because DV has already converted YAML birthday to DateTime object
    // shouldn’t harm if already a string
    var bday = moment(birthday.toString());
    var bdayNext = moment(bday).year(start.year());
    if (bdayNext.isBefore(start, 'day')) {
        bdayNext.add(1, "year");
    }
    return bdayNext;
}

function turns(birthday) {
    // Get the age in years a person will turn to on their next birthday

    // need to "unparse" because DV has already converted YAML birthday to DateTime object
    // shouldn’t harm if already a string
    var bday = moment(birthday.toString());
    return nextBirthday(birthday).diff(bday, 'years');
}

function showBirthday(birthday) {
    // Determine if this birthday is in the range to be shown
    // including the start date, excluding the end date
    // because that comes from a duration calculation
    // for use with "where", returns true or false
    
    if (birthday) {
        // need to "unparse" because DV has already converted YAML birthday to DateTime object
        // shouldn’t harm if already a string
        var bday = moment(birthday.toString());
        var bdayNext = nextBirthday(birthday);
        if (bdayNext.isBetween(start, end, 'day', '[)')) {
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

function sortByNextBirthday(a, b) {
    // comparator function for "sort"
    
  if (nextBirthday(a).isBefore(nextBirthday(b))) {
    return -1;
  }
  if (nextBirthday(a).isAfter(nextBirthday(b))) {
    return 1;
  }
  // they’re equal
  return 0;
}

//======================================================================

dv.paragraph(infotext.format(moment.duration(dv.current().duration.toString()).humanize(), start.format(dateformat), end.format(dateformat)));

dv.table(
    ["Name", "Birthday", "Turns"],
    dv.pages(dv.current().searchterm)
        // use a function to see if this birthday is in range to be shown
        .where(p => showBirthday(p.birthday))
        // use a comparator function to sort by next birthday
        .sort(p => p.birthday, 'asc', sortByNextBirthday)
        .map(p => [
            p.file.link,
            p.birthday ? nextBirthday(p.birthday).format(dateformat) : '–',
            turns(p.birthday)
        ])
);

```

## Notes

- Dataview actually _parses_ the cell content, so if you for example set the date format to `D. MMMM`, you’ll get large vertical spacing. This is because DV _thinks_ something like `17. May` must be an _ordered list item_ and parses it accordingly. Which in turn will ruin your vertical spacing.  
See [0.3.3: table item converts to ordered list, ruining vertical spacing · Issue #199 · blacksmithgu/obsidian-dataview · GitHub](https://github.com/blacksmithgu/obsidian-dataview/issues/199).

- Using durations \> 1 year (like `2 years`) _work_, but don’t make much sense. The table will only display a person’s _next_ birthday. So no duplicates.

---

<div class="post-metadata">

**Author:** ![kastyb](https://forum.obsidian.md/letter_avatar_proxy/v4/letter/k/a3d4f5/32.png) [@kastyb](https://forum.obsidian.md/u/kastyb)\
**Post date:** [May 9, 2021, 9:09pm UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/7 "2021-05-09T21:09:28Z")

</div>

Hello! I have a “How-to” question.

```auto
for (let group of dv.pages("#test1").groupBy(p => p.subject)) {
    dv.header(5, group.key);
    dv.table(["Name", "Author", "Link"],
        group.rows	
          
            .map(k => [k.file.link, k.author, 
			k.URL]
))
}

```

This is the output of the code.

 ![Capture](https://forum.obsidian.md/uploads/default/original/2X/f/ff3a246886aaf4ed4e700fe959d4f27e1090e6bd.jpeg)

How do we get a hyperlink instead of the long URL. With the “normal” dataview we could wrap the URL with a desired sting using elink() function. How do we emulate that in dataviewjs?

---

<div class="post-metadata">

**Author:** ![Moonbase59](https://forum.obsidian.md/user_avatar/forum.obsidian.md/moonbase59/32/13648_2.png) [@Moonbase59](https://forum.obsidian.md/u/Moonbase59)\
**Post date:** [May 9, 2021, 9:22pm UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/8 "2021-05-09T21:22:57Z")

</div>

Well, instead of `k.URL` you could use something like

```auto
"Link".link(k.URL)

```

where `"Link"` could even come from a variable or calculation, enclosed in parentheses, like

```auto
(k.author).link(k.URL)

```

effectively making the author clickable and saving a column.

I use this technique in my [Show family members, friends and places that are _nearby_](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/2) example above.

_Note:_ In olden times, `.link` wasn’t supported too well in each and every browser. Fortunately, Electron (and thus Obsidian) handles it well.

---

<div class="post-metadata">

**Author:** ![kastyb](https://forum.obsidian.md/letter_avatar_proxy/v4/letter/k/a3d4f5/32.png) [@kastyb](https://forum.obsidian.md/u/kastyb)\
**Post date:** [May 10, 2021, 1:08pm UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/9 "2021-05-10T13:08:03Z")

</div>

Thank you so much! This will save unnecessary horizontal scrolling to view all the rows.

---

<div class="post-metadata">

**Author:** ![Rishi](https://forum.obsidian.md/user_avatar/forum.obsidian.md/rishi/32/398_2.png) [@Rishi](https://forum.obsidian.md/u/Rishi)\
**Post date:** [May 10, 2021, 3:47pm UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/10 "2021-05-10T15:47:19Z")

</div>

> [@Moonbase59](#):
>
> ```auto
> 
> ```
> 
> #searchterm: “#family or #friends”  
> searchterm: ‘“People”’
> 
> ```auto
> 
> ```

Why does the YAML have both these?

---

<div class="post-metadata">

**Author:** ![Moonbase59](https://forum.obsidian.md/user_avatar/forum.obsidian.md/moonbase59/32/13648_2.png) [@Moonbase59](https://forum.obsidian.md/u/Moonbase59)\
**Post date:** [May 11, 2021, 5:17am UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/11 "2021-05-11T05:17:07Z")

</div>

Because I’m currently testing and it’s much easier just to comment/uncomment things. 😉  
I also wanted to show how a tag search and a folder search would look like.

---

<div class="post-metadata">

**Author:** ![Rishi](https://forum.obsidian.md/user_avatar/forum.obsidian.md/rishi/32/398_2.png) [@Rishi](https://forum.obsidian.md/u/Rishi)\
**Post date:** [May 11, 2021, 6:12am UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/12 "2021-05-11T06:12:36Z")

</div>

Oh I figured it after posting this! I was getting some weird error and was eliminating all possible options that might cause it. Thanks for sharing the code.

Do you happen to know if we can use DataviewJS inline like we could Dataview queries? I’ve been using Templater to have inline “Next Birthday” in individual People note but Templater dynamic templates break all table formatting right now.

---

<div class="post-metadata">

**Author:** ![Moonbase59](https://forum.obsidian.md/user_avatar/forum.obsidian.md/moonbase59/32/13648_2.png) [@Moonbase59](https://forum.obsidian.md/u/Moonbase59)\
**Post date:** [May 16, 2021, 2:02am UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/13 "2021-05-16T02:02:40Z")

</div>

## List(s) of Obsidian Commands

**EDIT:** _A newer and better version is [down in post #37](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/37)!_

I needed a list of currently enabled Obsidian Commands (those in the Command Palette, internal plus plugins). So I thought »Why not do it using Obsidian itself (and Dataview)?«

### Commands sorted by internal Command ID

```javascript

const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce((obj, key) =>
        (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}

function getHotkey(arr) {
    return arr.hotkeys ? [[getNestedObject(arr.hotkeys, [0, 'modifiers'])],
    [getNestedObject(arr.hotkeys, [0, 'key'])]].flat(2).join('+').replace('Mod', 'Ctrl') : '–';
}

let cmds = dv.array(Object.entries(app.commands.commands))
    .sort(v => v[1].id, 'asc');

dv.paragraph(cmds.length + " commands currently enabled.<br><br>");

dv.table(["Command ID", "Name in current locale", "Hotkeys"],
  cmds.map(v => [
    v[1].id,
    v[1].name,
    getHotkey(v[1]),
    ])
  );
 

```

Result:

 ![obsidian-dataview-command-list-by-id](https://forum.obsidian.md/uploads/default/original/2X/9/941d1ddfba27d5caab7bc258634ac95fb017525d.png)

### Commands sorted by assigned hotkey

This I missed the most. Just to check if a planned hotkey combo is already taken …

```javascript

const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce((obj, key) =>
        (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}

function getHotkey(arr) {
    return arr.hotkeys ? [[getNestedObject(arr.hotkeys, [0, 'modifiers'])],
    [getNestedObject(arr.hotkeys, [0, 'key'])]].flat(2).join('+').replace('Mod', 'Ctrl') : '–';
}

let cmds = dv.array(Object.entries(app.commands.commands))
    .where(v => getHotkey(v[1]) != '–')
    .sort(v => v[1].id, 'asc')
    .sort(v => getHotkey(v[1]), 'asc');

dv.paragraph(cmds.length + " commands with assigned hotkeys.<br><br>");

dv.table(["Command ID", "Name in current locale", "Hotkeys"],
  cmds.map(v => [
    v[1].id,
    v[1].name,
    getHotkey(v[1]),
    ])
  );
 

```

Result:

 ![obsidian-dataview-command-list-by-hotkey](https://forum.obsidian.md/uploads/default/original/2X/8/86470033b38fd2b4ca5ec117606d210f2c4d349b.png)

## Notes

I’m on Linux and this is good enough for me. I leave remapping MacOS keys and/or adding nice `<kbd>…</kbd>` tags around the keys (but not the plus signs in between!) as an exercise for the reader. 😉

Anyway, it’s a good check what we have, and could well be a starting point for the [Buttons](https://github.com/shabegom/buttons) and [Obsidian Leaflet](https://github.com/valentine195/obsidian-leaflet-plugin) plugins to maybe invoke commands _language-independently_, using their _ID_. Because now we know it an can make a list!

(Bi- and multilingual people switch Obsidian’s language often, and it sucks that commands called up by their (locale-specific!) _name_ suddenly stop working.)

---

<div class="post-metadata">

**Author:** ![Rishi](https://forum.obsidian.md/user_avatar/forum.obsidian.md/rishi/32/398_2.png) [@Rishi](https://forum.obsidian.md/u/Rishi)\
**Post date:** [May 16, 2021, 8:33am UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/14 "2021-05-16T08:33:22Z")

</div>

This is a very thoughtful snippet from @Moonbase59 like always! I’ve added some symbols in this for the Mac Shortcuts,

```auto
const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce((obj, key) =>
        (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}

function getHotkey(arr) {
    return arr.hotkeys ? [[getNestedObject(arr.hotkeys, [0, 'modifiers'])],
    [getNestedObject(arr.hotkeys, [0, 'key'])]].flat(2)
	.join(' ')
	.replace('Mod', '⌘')
	.replace('Shift', '⇧')
	.replace('Alt', '⌥')
	.replace('Ctrl', '⌃')
	.replace('ArrowRight', '→')
	.replace('ArrowLeft', '←')
	.replace('ArrowUp', '↑')
	.replace('ArrowDown', '↓')
	.replace('Enter', '⏎')
	.replace('Tab', '⇥'): '–';
}

let cmds = dv.array(Object.entries(app.commands.commands))
    .where(v => getHotkey(v[1]) != '–')
    .sort(v => v[1].name, 'asc')
    .sort(v => getHotkey(v[1]), 'asc');

dv.paragraph(cmds.length + " commands with assigned hotkeys.<br><br>");

dv.table(["Command ID", "Name in current locale", "Hotkeys"],
  cmds.map(v => [
    v[1].id,
    v[1].name,
    getHotkey(v[1]),
    ])
  );

```

Although it works fine for me right now, except for sorting which needs some fixing, I’m sure I’m missing other symbols people might use,

 ![image](https://forum.obsidian.md/uploads/default/original/2X/a/a8df6efa3da551a26e7d70d0034beebb86765373.png)

[This](https://gist.github.com/Zenexer/c5243c4216f1f8cd2251) is a good place to find some of the common symbols if the built-in character viewer seems too much.

---

<div class="post-metadata">

**Author:** ![Productive](https://forum.obsidian.md/letter_avatar_proxy/v4/letter/p/f9ae1b/32.png) [@Productive](https://forum.obsidian.md/u/Productive)\
**Post date:** [May 21, 2021, 1:58pm UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/15 "2021-05-21T13:58:30Z")

</div>

Hi I built a quick script with dataviewjs to collate my daily note lists for my weekly note. It’s using regular expressions and the obsidian API to accomplish this. I’m pretty new to using javascript so any feedback will be appreciated.

```auto
//Set the beginning and end of the week
const beg = moment("2021-05-16")
const end = moment("2021-05-22")

//The RegEx that does the heavy lifting
const er = new RegExp(/##.Lists\n([\s|\S]*)##.[I|D]/g);
const re = new RegExp(/(?:####.*\n)(?:[-|\d.].*\n)*/g);

/*
My Lists look like this
## Lists
#### a list
- markdown
#### another list
- [] it catches these too
*/

//Obsidian's API has allows you to grab a file's parent
const par = app.vault.getAbstractFileByPath("Daily/2021-05-13.md").parent;

//Get the files for the week as a Map 
const week = par.children.reduce((acc,chil) => {
	let name = chil.basename;
	let date = moment(name);
	if (date >= beg && date <= end){
		acc.set(name,chil)	
	}
	return acc
},new Map())

const sortWeek = new Map([...week].sort((a,b) => String(a[0]).localeCompare(b[0])))

sortWeek.forEach((v,k,m) => {
	let path = app.vault.getAbstractFileByPath(v.path)
	app.vault.read(path)
	.then( fileText => {
		let listText = fileText.match(er)
		return new Promise((resolve,reject) =>{resolve(...listText)})
	})
	.then(listText => {
		const lists = listText.match(re);
		if (lists !== null){
			dv.header(4,k)
			dv.list(lists)
		}
	})
});

```

---

<div class="post-metadata">

**Author:** ![Moonbase59](https://forum.obsidian.md/user_avatar/forum.obsidian.md/moonbase59/32/13648_2.png) [@Moonbase59](https://forum.obsidian.md/u/Moonbase59)\
**Post date:** [May 22, 2021, 6:18am UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/16 "2021-05-22T06:18:05Z")

</div>

## Sortable columns—Note to myself

I’m using the really helpful [Sortable Plugin](https://github.com/alexandru-dinu/obsidian-sortable), so columns in my tables can be easily sorted in preview mode. It it in its early stages, but already quite practical to use.

Of course it won’t be able to sort columns with “odd” contents, like user-formatted dates, for instance.

Nevertheless, since we could write a **sort comparator function** in Javascript for these, within the code block, it should be a snap if the author of _Sortable_ could provide us with a hook to add our own comparator functions per column. And if we could access this within the “Dataview Javascript”.

I opened a [feature request for this](https://github.com/alexandru-dinu/obsidian-sortable/issues/12) on _Sortable_’s GitHub page. Maybe you’d like to support it.

Related:

- [About table sorting · Discussion #136 · blacksmithgu/obsidian-dataview · GitHub](https://github.com/blacksmithgu/obsidian-dataview/discussions/136)
- [Check integration with obsidian-dataview · Issue #6 · alexandru-dinu/obsidian-sortable · GitHub](https://github.com/alexandru-dinu/obsidian-sortable/issues/6)

---

<div class="post-metadata">

**Author:** ![hstagner](https://forum.obsidian.md/letter_avatar_proxy/v4/letter/h/a9a28c/32.png) [@hstagner](https://forum.obsidian.md/u/hstagner)\
**Post date:** [May 28, 2021, 2:37pm UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/17 "2021-05-28T14:37:31Z")

</div>

I’m looking to create a dataview table that I think can only be accomplished with Dataviewjs.

I have Literature Notes that look like this:

 ![image](https://forum.obsidian.md/uploads/default/original/2X/8/8ae6fb0f5c00559a6e97def0622b7cd9b36c2ec4.png)

I would like to show ALL Literature Notes in a table sorted descending by their “secondary tag” frequency. The secondary tags are all tags that are not “#litnote”. In this example the only secondary tag is “#writing” but some notes have more.

This is so I can find clusters of “Literature Notes” that belong to the same tag. I am at a loss at the moment to figure out how to associate the tags with the notes. I can grab the tags themselves and the notes themselves in js, but not the correlation between the two.

I hope this is clear. Thank you in advance for any help.

---

<div class="post-metadata">

**Author:** ![torantine](https://forum.obsidian.md/letter_avatar_proxy/v4/letter/t/b487fb/32.png) [@torantine](https://forum.obsidian.md/u/torantine)\
**Post date:** [June 3, 2021, 1:15am UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/18 "2021-06-03T01:15:52Z")

</div>

@Azulaloi was looking for a dataview snippet that would give the word count of all pages in a vault with a specific tag. Uses the guts of the Better Word Count Plugin by @lukeleppan. Works really well with MetaEdit to change the search term. Here is what I came up with: [dataviewjs.wordcountfromtag · GitHub](https://gist.github.com/gblakehl/af639cba3c32762576d64c34effaf614)

 ![dataviewjs-wordCountOtherPages-003](https://forum.obsidian.md/uploads/default/original/2X/d/d1bc9832ec9e0bf00562a0ea532657c4ff200199.gif)

---

<div class="post-metadata">

**Author:** ![cristian](https://forum.obsidian.md/user_avatar/forum.obsidian.md/cristian/32/6039_2.png) [@cristian](https://forum.obsidian.md/u/cristian)\
**Post date:** [June 4, 2021, 12:51pm UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/19 "2021-06-04T12:51:25Z")

</div>

Thanks for this!, one question.

Where I can know more about those ‘inline metadata fields’? they look simple and amazing 🙂

---

<div class="post-metadata">

**Author:** ![Moonbase59](https://forum.obsidian.md/user_avatar/forum.obsidian.md/moonbase59/32/13648_2.png) [@Moonbase59](https://forum.obsidian.md/u/Moonbase59)\
**Post date:** [June 11, 2021, 11:47pm UTC](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847/20 "2021-06-11T23:47:24Z")

</div>

Here’s another thread that shows how an idea evolves and _DataviewJS_ is used: @FiekeB and I were talking about how a recipe data collection could be set up.

> [@Help: #howto Build Recipe "database" in Obsidian (complex)](https://forum.obsidian.md/t/help-howto-build-recipe-database-in-obsidian-complex/19548):
>
> Build Recipe “database” in Obsidian \*I usually write in Dutch, but for the sake of being able to ask help on the Obsidian Forum, this one’s in English. I will translate it into Dutch to keep in my vault under “Culinair”, once I know how to set this up according to my wishes. #remindertoself \* Why I want to build this “database” of interlinked recipe and ingredient notes I have thousands of PDF Recipe books and also thousands of TXT recipes and lots of them in a recipe manager called Paprika. …

[Next page](https://forum.obsidian.md/t/dataviewjs-snippet-showcase/17847.md?page=2)
