Lazyload dataview/dvjs codeblock

I’m building a dvjs view and managed to add a lazy loading feature to it.

Since it can be useful for all resource intensive dvjs views (and dql queries), I thought of extracting its logic into a single file for easier use. Here it is:

const rootNode = dv.el("div", "");
const viewObserver = new IntersectionObserver((entries) => {
	entries.map((entry) => {
		if (entry.isIntersecting) {
			viewObserver.unobserve(entries[0].target);
			input()
		}
	});
});
viewObserver.observe(rootNode)

To use it you’ll need to save this in a .js file somewhere in your vault. You can name it the way you want (mine is saved at this path inside my vault _js/lazyload.js). Then to “convert” your codeblock and make it lazyloaded, you’ll need to do 2 things:

  1. Put all the code from your codeblock inside a function (don’t forget to make it async if needed)
  2. Call the view to lazyload your function

So for example, you should go from this:

```dataviewjs

const amountOfImages = 3;
const attachmentFolderPath = app.vault.getConfig("attachmentFolderPath");
const imageFiles = app.vault
	.getFiles()
	.filter(file => {
		return file.extension !== 'md'
			&& file.parent.path.startsWith(attachmentFolderPath)
	})

dv.list(dv.array(imageFiles)
	.sort(() => 0.5 - Math.random())
	.limit(amountOfImages)
	.map(file => dv.func.embed(dv.fileLink(file.path))))

```

P.S 1: The original code from this codeblock was taken from here: obsidian_dataview_example_vault/Display random images from a path.md at main · s-blu/obsidian_dataview_example_vault · GitHub (fantastic resource btw)

P.S. 2: Don’t try using it on iPad, it crashes the app (for unkown reasons)

to this:

```dataviewjs

function f() {
	const amountOfImages = 3;
	const attachmentFolderPath = app.vault.getConfig("attachmentFolderPath");
	const imageFiles = app.vault
		.getFiles()
		.filter(file => {
			return file.extension !== 'md'
				&& file.parent.path.startsWith(attachmentFolderPath)
		})
	
	dv.list(dv.array(imageFiles)
		.sort(() => 0.5 - Math.random())
		.limit(amountOfImages)
		.map(file => dv.func.embed(dv.fileLink(file.path))))
}

await dv.view("_js/lazyload", f)

```

From now on, the code within your function will not be triggered until the code block is visible in your window, and yes, it works with closed callouts!

Note that this solution rely on the injection of an empty div at the top of the codeblock to keep track of wether or not to trigger your function. It might break the logic of your dvjs view if you are doing dom manipulation inside it.

Dataview DQL support

This solution only works with dataviewjs. If you want to lazyload your dataview query, you can do the following:

  1. Verify that you you have Enable JavaScript Queries enabled it dataview’s settings
  2. Replace input() to dv.execute(input) at the 6th line of the script
  3. Change dataview to dataviewjs at the top of your view
  4. Instead of encapsulating your code in a function, you will want to convert your entire DQL code into a string and store it in a variable:

from this:

```dataview
LIST
FROM ""
WHERE file.size = 0
```

to this:

```dataviewjs
const dql = `LIST
FROM ""
WHERE file.size = 0`

await dv.view("_js/lazyload", dql)
```

N.B. Obsidian already does a lazy loading of the file content, so if you have a long file and your code block is at the very bottom, it won’t be loaded into the DOM in the first place.

3 Likes