Dynamically generate JDex file from JDex notes in Obsidian

I’m fiddling with implementing JD in Obsidian for my personal and academic duties. I chose the “one note per ID” strategy, because it looks the easiest. However, I realised that I would still like to have an index file, so that it is quicker to scan through the IDs on mobile.

After a bit of online search, I implemented a dynamic index file via the Dataview plugin (with dataviewjs enabled).

Here is a test vault with the structure:

The 00.00 Index.md file looks like this:

# Index

```dataviewjs
let categories = dv.pages('"00-09 System management/00 Meta-system/00.01 Index notes"')
    .sort(p => p.file.name)
    .groupBy(p => p.file.frontmatter.jdcategory)

let areas = dv.pages('"00-09 System management/00 Meta-system/00.01 Index notes"')
    .sort(p => p.file.name)
    .groupBy(p => p.file.frontmatter.jdarea)

for (let area of areas) {
    dv.header(2, area.key);
	let areaNum = Math.floor(Number(area.key.slice(0, 2)) / 10);
    for (let category of categories) {
	    let catNum = Math.floor(Number(category.key.slice(0, 2)) / 10);
	    if (areaNum == catNum) {
		    dv.header(3, String(category.key).padStart(2, '0'));
		    dv.list(
		       category.rows
		       .sort(k => k.file.name)
		       .map(k => k.file.link + ": " + k.file.frontmatter.jddescription)
		   )
		}
   }
}
```

For this to work, each JDex ID entry note should have

---
jdarea:
jdcategory:
jddescription:
tags:
---

in the YAML frontmatter.

The pros I found for this approach are:

  • I am less likely to duplicate IDs, because I can take a look at the used ones first from any device;
  • by copying the dynamic result and pasting it elsewhere, I obtain a static single-file JDex.

There are cons, of course:

  • creating a new entry takes more time;
  • if Obsidian is not available, one still needs to scan the entries’ folder and look for an empty ID.
3 Likes

Very cool. Next we need a clean-up script for when I just slam a note in with just the xx.yy identifier and don’t take the time to do the front matter. :stuck_out_tongue:

2 Likes

For that, I use the stock Templater plug-in and use the command palette to forcefully insert the jdex-slip template

---
jdarea:
jdcategory:
jddescription:
tags:
---

# <!-- Insert ID name here -->
## Location
- Obsidian notes
- 

## Quick notes
1 Like

Nice!

I do something very similar, although I make notes for areas and categories as well. It gives me a nice place to describe the area/category, its scope etc. I also use data view inside these to list its categories (for areas) or IDs (for categories).

I’ve uploaded a sample to Github. It looks like this:

There are some templates that I use for creating the index notes as well, and (obviously) the Dataview JS code.

Hope someone find it useful!

2 Likes

Here is my dataviewjs version, it’s based on Life Admin version with notes for are/categories/ids and I added #type/index tag to all of them.
Script also adds highlighting to header ids.

function formatItem(i) {
	let typeMark = "";
	if (i.file.name.indexOf('■') > -1) {
		return `==${i.file.link}==`;
	}
	return `${i.file.link}`;
}
let pages = dv.pages("#type/index").sort(p => p.file.name, "asc");

const by_area = pages.groupBy((p) => p.file.folder.split('/')[0])



for (let area of by_area) {
    dv.header(3, area.key);
    const by_category = area.rows.groupBy((p) => p.file.folder.split('/')[1]);
    for (let category of by_category) {
 	    const categoryRoot = dv.el("ul", "");
	    const categoryRootLi = dv.el("li", `[[${category.key}]]`, {container: categoryRoot});
	    const idRoot = dv.el("ul", "", {container: categoryRootLi});
	    for (let id of category.rows) {
		    dv.el("li", formatItem(id), {container: idRoot});
	    } 
    }
}

1 Like