Dataview/dataviewjs: How to fetch Tasks that are in the outgoing links of a note

What I’m trying to do

I have a note (note name: “test1”) where there are some tasks and also some outgoing links to other notes (“test2”, “test3”, etc). These other notes have some tasks of their own. And I want to see all the tasks that are in notes “test1”, “test2”, and “test3” (and other outgoing links) in the note (“test1”) with dataview. How can I do that?

A small table for example showing what I am doing.

Note Name test1 test2 test3
Tasks clean house do dishes do homework
Outgoing Links test2, test3 - -
Dataview in here - -

So the desired output from the dataview is:

  • clean house
  • do dishes
  • do homework

Things I have tried

I used the TASK function with WHERE file.name = string(this.file.outlinks[0]). Here I tried with string() because this.file.outlinks returns an array and it seems file.name only accepts texts. I also understand that the array has many values so I tried seeing if I can get atleast one value converted to text but that didn’t work. The whole command looks like this:

```dataview
TASK
WHERE file.name = string(this.file.outlinks[0])

I tried seeing the output of inline dataview output of string(this.file.outlinks[0]) and it seems that the output is a link file. I think that is an issue? But then again, I feel like this still won’t give me the final answer that I am looking for which is seeing tasks from all the outgoing links. Can someone point me to the right direction?

Thank you.

Small update:

I found that this.file.outlinks[0].file.name converts the links to texts.

And the following dataview shows the tasks from note “test2”:

```dataview
TASK
WHERE file.name = this.file.outlinks[0].file.name

But that doesn’t solve my main question :\ … how can I get it to work easily for as many outgoing links in the note?

Small update 2 (trying out dataviewjs):

```dataviewjs
dv.taskList(dv.current().file.tasks
  .where(t => !t.completed))

This seemed to show the tasks of the note where it is ran. How can I say this code to fetch the the tasks from outgoing links?

Update (Got it to work! Though would appreciate if an expert checks it out):

Okay I think I found the answer! Though would appreciate if someone can check it out for any errors and/or improves the code :smile:

The following command gives the desired output:

```dataviewjs
const first = dv.current().file.link;
dv.taskList(dv.page(first).file.tasks
.where(t => !t.completed));

const notes = dv.current().file.outlinks;
let note = 'empty';
for (note of notes) 
	dv.taskList(dv.page(note).file.tasks
	.where(t => !t.completed));
```

Here,

  • first is the “test1” note and the first half of the code outputs the “test1” tasks.
  • notes is all the outgoing link notes (eg. “test2”, “test3”) and the second half of the code outputs their tasks.

Here’s the output of the code:

Update (Code works but a bit off):

I checked the task in “test3” as completed and now it shows this huge “Dataview: No results to show for task query” in place of “test3” block. It takes up a lot of space in the note. How can I remove this?

Here’s the output after checking task in"test3":

small update:

found this forum answer saying there is an option in the Dataview Settings where you can turn off the “Warn on Empty Results” universally for all notes in the vault.

Though I don’t want to do that for all notes. Is there a way I can use dataviewjs to not show the No result warning?

I think you can check the length of the task list is > 0 and then decide to render or not based on that

1 Like

Just woke up a few minutes back. Can you point me to the direction with the length function documentation?

I have tried length() and dv.length(), they didn’t work (“length is not a function”). I also tried googling but so far nothing :\ …

Update (found a way to find length but what I need is to find the length of not-completed tasks only):

So, it seems that what works to find length is: .length at the end of the value part (though would apperciate an explanation as to why that is. I just randomly did it and it worked). Checking the output of .length with an inline dataview js:

$= dv.paragraph(dv.page("test3").file.tasks.length)

This outputs “1”.

But that means it is showing the length of total tasks (i.e. completed and not-completed, together). So the “No result to show task query” still shows for “test3” note.

How can i modify the code to only show length of not-completed tasks?

Right now, my code looks likes:

```dataviewjs
const first = dv.current().file.link;
dv.taskList(dv.page(first).file.tasks
.where(t => !t.completed));

const notes = dv.current().file.outlinks;
let note = 'empty';
for (note of notes) {
	
	if(dv.page(note).file.tasks.length > 0) {
		dv.taskList(dv.page(note).file.tasks
		.where(t => !t.completed));
	}
	else {
		dv.paragraph("no result")
	}
}
```

Update (Got it to work! So glad :smile: ):

So to get the length of only not-completed tasks, we have to first write .where(t => !t.completed) and then check the length with .length. So, let’s check that in inline dataviewjs:

$= dv.paragraph(dv.page("test3").file.tasks.where(t => !t.completed).length)

this outputs “0”. which means there are 0 not-completed tasks!

So now, the Working code looks like:

```dataviewjs
const first = dv.current().file.link;
dv.taskList(dv.page(first).file.tasks
.where(t => !t.completed));

const notes = dv.current().file.outlinks;
for (let note of notes) {
	if(dv.page(note).file.tasks.where(t => !t.completed).length > 0) {
		dv.taskList(dv.page(note).file.tasks
		.where(t => !t.completed));
	}
}
```

NOTE!
I have removed the previous

let note = "empty"

and instead placed it inside the for loop :

for (let note of notes)

Bonus:Slightly improved code

If in your note you are wiki-linking to the same note you are on, like the following picture:

image

Then you may see two same Tasks entries of the note, like:

because in the code:

  • the first variable shows the tasks of “test1” note.
  • and note variable shows the tasks of all the linked note including “test1” which is the same note.

To fix this

We have to check if the linked note note matches the current note which is first. We do this with an if statement:

if(dv.page(note).file.name != first) {}

So, now, the final code looks like this:

```dataviewjs
const first = dv.current().file.name;
dv.taskList(dv.page(first).file.tasks
.where(t => !t.completed));

const notes = dv.current().file.outlinks;
for (let note of notes) {
	if(dv.page(note).file.name != first){
		if(dv.page(note).file.tasks
		.where(t => !t.completed).length > 0) {
			dv.taskList(dv.page(note).file.tasks
			.where(t => !t.completed));
		}
	}
}
```

NOTE!

I have also changed the first line const first = dv.current().file.link to:

const first = dv.current().file.name

Because .file.link and .file.name are basically the same thing except they are of different data type.
.file.link will output a link whereas .file.name will output a string.

Small update (image link in note causes error):

I am facing an issue where pasting an image link in the note makes the code output error (because of the for loop presumably):

Evaluation Error: TypeError: Cannot read properties of undefined (reading 'file')

I am opening a different question in the forum for that. (here)

MAJOR UPDATE:

Using const will make the variable constant. And so if you change the name of the note, then you will always have to reload the dataviewjs for the code to work. So, change all const to let.

The code looks like this now:

```dataviewjs
let first = dv.current().file.name;
let firstTask = dv.current().file.tasks.where(t => !t.completed)
if(firstTask.length > 0) {
	dv.taskList(firstTask);
}


let notes = dv.current().file.outlinks.where(x => !x.path.endsWith("png"));
for (let note of notes) {
	if(dv.page(note).file.name != first){
		let ntask = dv.page(note).file.tasks.where(t => !t.completed);
		if(ntask.length > 0) {
			dv.taskList(ntask);
		}
	}
}
```

Note

added firstTask to prevent the “dataview: no result to show for task query” warning from showing for the first note.

1 Like

Major update (fixed: the outlinks show duplicates of a note if you have wikilinked those notes twice or more):

If, lets say, you wikilinked a note “test2” twice in your current note, it will show up twice in your outlink output. so to get around that you can use a combination of filter(), findIndex(), and indexOf() functions to get unique elements.

(For an explanation on how the functions works, see here)

with filter() and findIndex() function:

let notes = dv.current().file.outlinks
.filter((value, index, self) => index === self.findIndex(t => t.path === value.path))
.where(x => !x.path.endsWith("png"));

with filter() and indexOf() function:

let notes = dv.current().file.outlinks
.map(x => x.path)
.filter((value, index, self) => index === self.indexOf(value))
.where(x => !x.endsWith("png") && x != dv.current().file.path);

with only indexOf() function:

// getting all outlinks without .png and current note
let notes = dv.current().file.outlinks.where(x => !x.path.endsWith("png") && x.path != dv.current().file.path);

// get only the unique outlinks
let paths = notes.map(x => x.path);
let unique = [];
paths.map(x => (unique.indexOf(x) === -1) && unique.push(x));

Editing and adding these lines will make the code work! Cheerio!


My current dataviewJS Code:

By the way, I further edited the code so now it looks like this:

```dataviewjs
// printing tasks from current note
let first = dv.current().file.name;
let firstTask = dv.current().file.tasks.where(t => !t.completed);
(firstTask.length > 0) && dv.taskList(firstTask);

// get unique outlinks without .png and current note
let notes = dv.current().file.outlinks
.filter((value, index, self) => index === self.findIndex(t => t.path === value.path))
.where(x => !x.path.endsWith("png") && x.path != dv.current().file.path);

// printing tasks from unique outlinks
let ntasks = notes.map(x => dv.page(x).file.tasks.where(t => !t.completed));
ntasks.map(x => x.length > 0 && dv.taskList(x));
```

A little bit of explanation of the changes:

  • the for loop is replaced with .map() function.
  • if statement is replaced with ‘and’ operator &&.
  • using filter() with findIndex().
  • renaming tasks to ntasks to avoid confusion with .file.tasks
  • use of arrow functions
1 Like

Minor Update (further optimized the code):

I further optimized the code by:

  • removing the need of a separate section in code for showing current note tasks by
    • creating an empty array,
    • pushing the current file path, and
    • pushing each of the outlink elements into the empty array
  • then showing the tasklist of the new array that contains the paths of the current file and all unique outlinks
```dataviewjs
// get all unique outlinks without .png and current note
let notes = dv.current().file.outlinks
.map(x => x.path)
.filter((value, index, self) => index === self.indexOf(value))
.where(x => !x.endsWith("png") && x != dv.current().file.path);

// create empty array
let arr = [];

// push notes element to empty array
arr.push(dv.current().file.path);
notes.map(y => arr.push(y));

// printing tasks from unique outlinks
let ntasks = arr.map(x => dv.page(x).file.tasks.where(t => !t.completed));
ntasks.map(x => x.length > 0 && dv.taskList(x));
```
1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.