Re-use dataview js script that uses Obsidian Charts

What I’m trying to do

I’m trying to convert a script that I use in daily notes as a re-usable script. This script generates a pie chart based on the notes that I have in the respective daily note markdown file. Below is how I use my code, and I’m able to successfully execute it if I directly write it in a code block in the daily note. But when I try to re-use it using dv.view(), I’m getting error, only for the code that uses Obsidian Charts.

Things I have tried

dv.view("Scripts");

view.js file in Scripts folder:

const chartData = {  
    type: 'doughnut',
	data : {
	  labels : labels,
	  datasets : [ {
	    backgroundColor : randColors,
	    data : data
	  } ]
	}
}


dv.el("h4", "Task Type Chart");
window.renderChart(chartData, this.container);

I’m getting the below error :

Dataview: Error while executing view ‘Scripts/view.js’.

TypeError: Cannot read properties of undefined (reading ‘createEl’)

Screenshot of error showing that the vanilla dataview is rendered fine

What I understand is that dataview isn’t able to create a new element in current window, since the code in external. How do I solve this>

What worked for me is to use dv.io.load to load the JavaScript file and use dv.executeJs to execute it.

dv.executeJs(await dv.io.load("Scripts/folder/filename.js"))

OLD

Another solution to this seems to be wrapping the entire script in the function:

dv.executeJs(`
// write your code here
`)l

Reference: Dataview: reuse DQL queries?

1 Like

Using dv.view() is a better option for reusability, but you need to pass the proper data to the script file. It’s a matter of a variable scoping, and passing along what’s needed for the dv.view() to function properly.

Put another way, instead of just doing dv.view("Scripts"), you need to do something like dv.view("Scripts", data) (or even more elaborate versions like dv.view("Scripts", { data: myDataVariable, type: "line" }) ). The data would then be available within the script through the input variable.

Thank you for input holroy.
Can you let me know whats the difference between dv.view() and dv.executeJs and why is dv.view() a better option?

I consider dv.view() a better option since it becomes a static call wherever you insert it, while it still allows for the actual query to be dynamic.

For example in my daily notes I’ve got a call to await dv.view("_js/journalHeaderNav") which builds a header to navigate my journal entries. I always want to have a header, but how I want that to look might change. Using dv.view() I can now just change the _js/journalHeaderNav.js file, and all pages linking (through the dv.view()call) will be updated.

I’ve not used dv.executeJs, and I can see a use if you’re generating the query somehow. It could potentially be useful (from my point of view), if you “import” the source into it (like you did using await dv.io.load(...)). Like if you have another note holding the actual query, and then load that note, and use it in a call to dv.executeJs. Then again, that is the functionality provided by dv.view(). Differences does come down to variable scoping, and what’s available in either version. I’ve not looked a whole lot into that, but I feel that the the dv.view() is the cleaner solution, when javascript is the query language.

A similar approach could possible be used by dv.execute() if you’re more into DQL. That it, let another note hold the actual query, and then in the pages where you want to use that query, you do some variant of dv.execute() where the source is lifted/imported from the query note.

1 Like

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