How to find out the reference near dataviewjs block?

I have the following markdown text in my note:

- [[Dumbbell Shrug]]
  ```dataviewjs
  await cJS(({WorkoutsPreviousExercise}) => WorkoutsPreviousExercise.render(dv, 'Dumbbell Shrug'))
  ```
  - [x] [weight :: 24] [reps :: 25] asd
  - [x] [weight :: 21] [reps :: 28] bar

- [[Bicep Curl]]
  ```dataviewjs
  await cJS(({WorkoutsPreviousExercise}) => WorkoutsPreviousExercise.render(dv, 'Bicep Curl'))
  ```
    - [x] [weight :: 7] [reps :: 12] geaa
    - [x] [weight :: 21] [reps :: 9] cccc
    - [x] [weight :: 15] [reps :: 18] cccc

Each exercise is an element in a list. Now I have to specify exercise name twice: once as a link and twice as a string in the javascript snippet (I’m doing dv.page on it inside). Is there a way to figure out the nearest link near the specific dataviewjs block, so that I don’t have to write Dumbbell Shrug twice?

I can’t create a link dynamically, so it has to be in markdown. Otherwise I will not be able to use it when navigating between linked pages using javascript.

Given that your query and the list items you want to do the query on are both having the same list parent (it seems), you might be able to utilise that somehow and avoid having to write anything in the query. Just rely on the position of the query related to the list items (or repetitions of that set).

It’s not trivial javascript, but it shouldn’t be too hard either. Try looking at the parent member of a given list item for starters.

I’ve tried something like this: this.component.containerEl.parent but it’s undefined, appears like dataviewjs during execution is not attached to the document DOM. Any tips how to get to that parent?

Hmm… Looked a little more into this, and it was way harder to locate the whereabouts of the query than I thought. There could be something simple I’ve missed, but I can’t seem to find it just now.


What is it that your script actually does? Can it possible be solved in another way? Could you explain a little more on what the script would produce of output, and what the lines below your query indicates?

Would it suffice to let the script print the link, and not have it on the outside at all? Or is there something within the script which requires the link to be present for it to work?

After a little more searching I found this issue: Get position / line of inline query · Issue #2485 · blacksmithgu/obsidian-dataview · GitHub, which sadly enough is still unresolved. That kind of indicates it’s not easy to locate.

I then went into the source code of Dataview, and found that an inline query after a few twists and bends ends up doing this:

    public async executeJs(
        code: string,
        container: HTMLElement,
        component: Component | MarkdownPostProcessorContext,
        filePath: string
    ) {
        if (isDataviewDisabled(filePath)) {
            renderCodeBlock(container, code, "javascript");
            return;
        }
        const renderer = new DataviewJSRenderer(this, code, container, filePath);
        renderer.load();
        component.addChild(renderer);
    }

What’s interesting here is that the location of the javascript code is contained within the component part, and if I read the code correctly that is not passed into the DataviewJSRenderer() indicating that it’s not going to store any information about the location into the rendered object (aka in a place where we can access it later on).

It’s only added into the component hierarchy as a rendered object. So I guess that concludes that it’s not very easy to get to the location of the query within the source text.

You could of course try to re-read the entire file from within the query, locate your code block and parse the surrounding areas. It wouldn’t be an elegant solution, and would require some unique tag within the code block itself so as to properly identify the correct variant, and I’m not sure it’s worth the effort.

Another approach would be to leave an anchor on the line which you want to find the link of. Lets rewrite your example into this variant:

- [[Dumbbell Shrug]] #x/DS
  ```dataviewjs
  await cJS(({WorkoutsPreviousExercise}) => WorkoutsPreviousExercise.render(dv, 'DS'))
  ```
  - [x] [weight :: 24] [reps :: 25] asd
  - [x] [weight :: 21] [reps :: 28] bar

- [[Bicep Curl]] #x/BC
  ```dataviewjs
  await cJS(({WorkoutsPreviousExercise}) => WorkoutsPreviousExercise.render(dv, 'BC'))
  ```
    - [x] [weight :: 7] [reps :: 12] geaa
    - [x] [weight :: 21] [reps :: 9] cccc
    - [x] [weight :: 15] [reps :: 18] cccc

Now you could use CSS to hide any #x/* tags, and use something along the lines of dv.current().file.lists.where(m => i.tags.includes("#x/...").map(i => i.outlinks[0]) to pull out the link from the list item with the given tag (which you should store in a variable instead of my hardcoded variant). This way you would only need to repeat the tag ID in your call to WorkoutsPreviousExercise, and the link would still be statically included in the markdown.

To hide all those nested tags you could use something like:

[class*="cm-tag-x"],
[href^="#x/"] {
  /* background-color: green !important; /* */
  display: none; /* */
}

The first selector is for live preview, and the second selector is for reading mode. Since the first variant use substring matching, you do need to make sure that you got a leading prefix of the tag, which you don’t use elsewhere in your notes. Or you could potentially list all the variants, like in:

[class*="cm-tag-xDS"],
[class*="cm-tag-xBC"],
...

This is deemed necessary due to how live preview removes the slash from the nested tag, and makes our life a little harder to match against them using CSS! :smiley: