Trying to retrieve Callout with DataView

I tried to see any examples on the internet or the documentation on DataView Plugin, but didn’t found any resource.

I’m willing to query specific type of callouts for my weekly routine.

Any guidance to to do that would help.

Thanks!

2 Likes

Could you describe a bit more what you are trying to do? Do you want to display the entire callout? A copy of it? Some pieces from it?

dataview looks for field names & values in your note, not arbitrary strings pf text like a callout name. The built-in Obsodian search can do text strings though! Could using the built-in Obsidian search for the name of the call-out work? (You can make search query blocks like dataview blocks.)
Another alternative: Could embedding the callout work?

I want to do simple query to get a lists of all the “questions/achievements/failure…” that I had in particular week.

Can you elaborate what do mean when " embedding the callout work?"

The search is nice, but I didn’t found a way to show the whole text of the callouts, nor a way to add time block. Is there to way to perform that?

2 Likes

I have the same idea / demand: the different callout types should be actionable / retrievable like additional task types.
Checklist allows different task lists by tagging, but callout type is already like an implicit “tag”.

I am to looking for a way to show specific callouts or admontions (like question, failure) and list and group similar callouts/adminitions in a separate ‘output-card’:

List of MyDangers:

  • some danger, link to card
  • some other danger, link to card

Where ‘dangers’ can be triggered from cards using admonitions like this:

```ad-danger
some danger
```

OR by cards using callouts like this:

> [!DANGER]
> some other danger

I’m trying to accomplish this with Dataview. Unfortunately “```ad-failure” so far :wink:
Any ideas?

You can use the method here to extract the list of achievements etc from your callouts:

You’ll need to change the regex to match what you’re looking for, but the method is the same.

Thank you for reaching out. I (yet) don’t understand how this works if I have more than one admonition/callout in a card and multiple bullets, for instance:

 ``` ad-abstract
 title: atomic summary
 * understanding how to query
 * another bullet
 ```
 ``` ad-danger
 title: main challenge(s)
 * some danger
 * some other danger
 ```

  1. First things first. For testing I have added this into a card ‘exploring list with dataview’:
    ## Gratitude
    ## what happend today?
    ## here’s what happened
    ## here’s what also happened

  2. Also for testing, I’ve added an ‘else’:

    // Output the header
    dv.header(2, file.basename)
    if (summary) {
     // Output the header and summary
     // dv.header(2, file.basename)
     dv.paragraph(summary[1].trim())
    } else {
     dv.paragraph(“some text”)
    }

Now I indeed get a list of all my card-titles & ‘some text’.
Unfortunately the card ‘exploring list with dataview’ - containing the \ ## here’s what happened - doesn’t show \ ## here’s what happened.

Any thoughts, before I will tweak the regex-function for listing the <li>'s under “ad-danger” and/or [!DANGER]… ??

Here’s a working demo using your specific example:

Dataview code and downloadable demo vault

2 Likes

Like a charm!
I replace (\w+) with the type of admonition, to list these per type.
I.T.H.A.N.K.Y.O.U. for the teaching.

Is there a way to make this pull multiple admonitions from the same note? right now it only pulls the first one found.
side Note: It also hates nested admonitions but I don’t currently have a need for those.

Sure, just change the first regex to be a global regex ('g'), and then loop through the results.

Demo vault updated: https://drive.google.com/file/d/1HvWT_WlxVRVTlJw-T2CCnyPfJRNi_kQJ/view?usp=sharing

```dataviewjs
// You can update this to filter as you like - filtering for just your daily notes would be good
const pages = dv.pages('#daily')

// This regex will find the contents of a specifically formatted callout
const regex = /\n```ad-(\w+)\r?\ntitle:(.+?)\r?\n(\*.+?)```/

const rows = []
for (const page of pages) {
    const file = app.vault.getAbstractFileByPath(page.file.path)
    // Read the file contents
    const contents = await app.vault.read(file)
    // Extract the summary via regex
    for (const callout of contents.match(new RegExp(regex, 'sg')) || []) {
        const match = callout.match(new RegExp(regex, 's')) 
        rows.push([match[2], match[1], match[3], page.file.link])
    }
}

dv.table(['Title', 'Type', 'Bullets', 'Link'], rows)
```
1 Like

This works find for me if dv.pages() doesn’t return any pages (ie. dataview returns an empty table), but as soon as I use either

const pages = dv.pages()

or

const pages = dv.pages('#someExistingTag')

I get:

Evaluation Error: TypeError: contents.match is not a function or its return value is not iterable
    at eval (eval at <anonymous> (plugin:dataview), <anonymous>:15:36)
    at async DataviewJSRenderer.render (plugin:dataview:19705:13)

I’ve tried googling the error, but haven’t found any dataview/obsidian specific information. Is there a way to easily display the value of pages? I tried dv.paragraph(pages) but that just error-ed.

First question, did you test using the demo vault in my post? If you download the demo vault and make no changes, does it function correctly?

No, I hadn’t tried the test vault because I am a bad person.

The test vault works. However it is also that case that, if I modify the test vault to be const pages = dv.pages() it gives the same error about contents.match. So there is still an issue there.

However the test vault does work fine with existing tags defined in both the YAML and the main text (so there is clearly something additional going on in my real vault).

As penance for my sins I offer a regex for anyone else who might be looking for it to catch callouts using the new syntax:

> [!NAME] title
> body
const regex = />\s\[\!NAME\]\s(.+?)((\n>\s.*?)*)\n/

Where you replace NAME with whatever the type of callout you are trying to collate (eg. INFO, NOTE, etc).

The whole script then becomes:

// You can update this to filter as you like - filtering for just your daily notes would be good
const pages = dv.pages('#daily')

// This regex will find the contents of a specifically formatted callout
// const regex = /\n```ad-(\w+)\r?\ntitle:(.+?)\r?\n(\*.+?)```/
const regex = />\s\[\!NAME\]\s(.+?)((\n>\s.*?)*)\n/

const rows = []
for (const page of pages) {
    const file = app.vault.getAbstractFileByPath(page.file.path)
    // Read the file contents
    const contents = await app.vault.read(file)
    // Extract the summary via regex
    for (const callout of contents.match(new RegExp(regex, 'sg'))) {
	    const match = callout.match(new RegExp(regex, 's')) 
	    rows.push([match[1], match[2], page.file.link])
    }
}

dv.table(['Term', 'Definition', 'Link'], rows)

Having played around some more. The script fails if dv.pages() returns one or more pages where the regex does not match anything and so content.match’s
“return value is not iterable” (as the error says). My very limited js is probably not up to working out how to fix the for loop so this doesn’t raise an error.

Sorry, that’s my mistake in the original code.

Just change the contents.match line to be:

for (const callout of contents.match(new RegExp(regex, 'sg')) || []) {

and that will solve the issue :slight_smile:

It’s saying:

“Loop through the items in contents.match, and if that isn’t an array then loop through this empty array [].”