Codeblock Reference
Dataview JavaScript Codeblocks are created using the dataviewjs
language specification for a codeblock:
```dataviewjs
dv.table([], ...)
```
The API is available through the implicitly provided dv
(or dataview
) variable, through which you can query for
information, render HTML, and configure the view.
Asynchronous API calls are marked with ⌛
.
Query
Query methods allow you to query the Dataview index for page metadata; to render this data, use the methods in the render section.
dv.current()
Get page information (via dv.page()
) for the page the script is currently executing on.
dv.pages(source)
Take a single string argument, source
, which is the same form as a query language source.
Return a data array of page objects, which are plain objects with all of the page fields as
values.
dv.pages() => all pages in your vault
dv.pages("#books") => all pages with tag 'books'
dv.pages('"folder"') => all pages from folder "folder"
dv.pages("#yes or -#no") => all pages with tag #yes, or which DON'T have tag #no
dv.pages('"folder" or #tag') => all pages with tag #tag, or from folder "folder"
Note that folders need to be double-quoted inside the string (i.e., dv.pages("folder")
does not work, but
dv.pages('"folder"')
does) - this is to exactly match how sources are written in the query language.
dv.pagePaths(source)
As with dv.pages
, but just returns a data array of paths of pages that match the given source.
dv.pagePaths("#books") => the paths of pages with tag 'books'
dv.page(path)
Map a simple path or link to the full page object, which includes all of the pages fields. Automatically does link resolution, and will figure out the extension automatically if not present.
dv.page("Index") => The page object for /Index
dv.page("books/The Raisin.md") => The page object for /books/The Raisin.md
Render
dv.el(element, text)
Render arbitrary text in the given html element.
dv.el("b", "This is some bold text");
You can specify custom classes to add to the element via cls
, and additional attributes via attr
:
dv.el("b", "This is some text", { cls: "dataview dataview-class", attr: { alt: "Nice!" } });
dv.header(level, text)
Render a header of level 1 - 6 with the given text.
dv.header(1, "Big!");
dv.header(6, "Tiny");
dv.paragraph(text)
Render arbitrary text in a paragraph.
dv.paragraph("This is some text");
dv.span(text)
Render arbitrary text in a span (no padding above/below, unlike a paragraph).
dv.span("This is some text");
dv.execute(source)
Execute an arbitrary dataview query and embed the view into the current page.
dv.execute("LIST FROM #tag");
dv.execute("TABLE field1, field2 FROM #thing");
dv.executeJs(source)
Execute an arbitrary DataviewJS query and embed the view into the current page.
dv.executeJs("dv.list([1, 2, 3])");
dv.view(path, input)
Complex function which allows for custom views. Will attempt to load a JavaScript file at the given path, passing it
dv
and input
and allowing it to execute. This allows for you to re-use custom view code across multiple pages. Note
that this is an asynchronous function since it involves file I/O - make sure to await
the result!
await dv.view("views/custom", { arg1: ..., arg2: ... });
If you want to also include custom CSS in your view, you can instead pass a path to a folder containing view.js
and
view.css
; the CSS will be added to the view automatically:
views/custom
-> view.js
-> view.css
View scripts have access to the dv
object (the API object), and an input
object which is exactly whatever the second
argument of dv.view()
was.
Bear in mind, dv.view()
cannot read from directories starting with a dot, like .views
. Example of an incorrect usage:
await dv.view(".views/view1", { arg1: 'a', arg2: 'b' });
Dataview: custom view not found for '.views/view1/view.js' or '.views/view1.js'.
Also note, directory paths always originate from the vault root.
Example
In this example, we have a custom script file named view1.js
in the scripts
directory.
File: scripts/view1.js
console.log(`Loading view1`);
function foo(...args) {
console.log('foo is called with args', ...args);
}
foo(input)
And we have an Obsidian document located under projects
. We'll call dv.view()
from this document using the scripts/view1.js
path.
Document: projects/customViews.md
await dv.view("scripts/view1", { arg1: 'a', arg2: 'b' })
When the above script is executed, it will print the following:
Loading view1
foo is called with args {arg1: 'a', arg2: 'b'}
Dataviews
dv.list(elements)
Render a dataview list of elements; accept both vanilla arrays and data arrays.
dv.list([1, 2, 3]) => list of 1, 2, 3
dv.list(dv.pages().file.name) => list of all file names
dv.list(dv.pages().file.link) => list of all file links
dv.list(dv.pages("#book").where(p => p.rating > 7)) => list of all books with rating greater than 7
dv.taskList(tasks, groupByFile)
Render a dataview list of Task
objects, as obtained by page.file.tasks
. By default, this view will automatically
group the tasks by their origin file. If you provide false
as a second argument explicitly, it will instead render them
as a single unified list.
// List all tasks from pages marked '#project'
dv.taskList(dv.pages("#project").file.tasks)
// List all *uncompleted* tasks from pages marked #project
dv.taskList(dv.pages("#project").file.tasks
.where(t => !t.completed))
// List all tasks tagged with '#tag' from pages marked #project
dv.taskList(dv.pages("#project").file.tasks
.where(t => t.text.includes("#tag")))
// List all tasks from pages marked '#project', without grouping.
dv.taskList(dv.pages("#project").file.tasks, false)
dv.table(headers, elements)
Renders a dataview table. headers
is an array of column headers. elements
is an array of rows. Each row is itself an array of columns. Inside a row, every column which is an array will be rendered with bullet points.
dv.table(
["Col1", "Col2", "Col3"],
[
["Row1", "Dummy", "Dummy"],
["Row2",
["Bullet1",
"Bullet2",
"Bullet3"],
"Dummy"],
["Row3", "Dummy", "Dummy"]
]
);
An example of how to render a simple table of book info sorted by rating.
dv.table(["File", "Genre", "Time Read", "Rating"], dv.pages("#book")
.sort(b => b.rating)
.map(b => [b.file.link, b.genre, b["time-read"], b.rating]))
Markdown Dataviews
Functions which render to plain Markdown strings which you can then render or manipulate as desired.
dv.markdownTable(headers, values)
Equivalent to dv.table()
, which renders a table with the given list of headers and 2D array of elements, but
returns plain Markdown.
// Render a simple table of book info sorted by rating.
const table = dv.markdownTable(["File", "Genre", "Time Read", "Rating"], dv.pages("#book")
.sort(b => b.rating)
.map(b => [b.file.link, b.genre, b["time-read"], b.rating]))
dv.paragraph(table);
dv.markdownList(values)
Equivalent to dv.list()
, which renders a list of the given elements, but returns plain Markdown.
const markdown = dv.markdownList([1, 2, 3]);
dv.paragraph(markdown);
dv.markdownTaskList(tasks)
Equivalent to dv.taskList()
, which renders a task list, but returns plain Markdown.
const markdown = dv.markdownTaskList(dv.pages("#project").file.tasks);
dv.paragraph(markdown);
Utility
dv.array(value)
Convert a given value or array into a Dataview data array. If the value is already a data array, returns it unchanged.
dv.array([1, 2, 3]) => dataview data array [1, 2, 3]
dv.isArray(value)
Returns true if the given value is an array or dataview array.
dv.isArray(dv.array([1, 2, 3])) => true
dv.isArray([1, 2, 3]) => true
dv.isArray({ x: 1 }) => false
dv.fileLink(path, [embed?], [display-name])
Converts a textual path into a Dataview Link
object; you can optionally also specify if the link is embedded as well
as it's display name.
dv.fileLink("2021-08-08") => link to file named "2021-08-08"
dv.fileLink("book/The Raisin", true) => embed link to "The Raisin"
dv.fileLink("Test", false, "Test File") => link to file "Test" with display name "Test File"
dv.sectionLink(path, section, [embed?], [display?])
Converts a textual path + section name into a Dataview Link
object; you can optionally also specify if the link is embedded and
it's display name.
dv.sectionLink("Index", "Books") => [[Index#Books]]
dv.sectionLink("Index", "Books", false, "My Books") => [[Index#Books|My Books]]
dv.blockLink(path, blockId, [embed?], [display?])
Converts a textual path + block ID into a Dataview Link
object; you
can optionally also specify if the link is embedded and it's display name.
dv.blockLink("Notes", "12gdhjg3") => [[Index#^12gdhjg3]]
dv.date(text)
Coerce text and links to luxon DateTime
; if provided with a DateTime
, return it unchanged.
dv.date("2021-08-08") => DateTime for August 8th, 2021
dv.date(dv.fileLink("2021-08-07")) => dateTime for August 8th, 2021
dv.duration(text)
Coerce text to a luxon Duration
; uses the same parsing rules as Dataview duration types.
dv.duration("8 minutes") => Duration { 8 minutes }
dv.duration("9 hours, 2 minutes, 3 seconds") => Duration { 9 hours, 2 minutes, 3 seconds }
dv.compare(a, b)
Compare two arbitrary JavaScript values according to dataview's default comparison rules; useful if you are writing a
custom comparator and want to fall back to the default behavior. Returns a negative value if a < b
, 0 if a = b
, and
a positive value if a > b
.
dv.compare(1, 2) = -1
dv.compare("yes", "no") = 1
dv.compare({ what: 0 }, { what: 0 }) = 0
dv.equal(a, b)
Compare two arbitrary JavaScript values and return true if they are equal according to Dataview's default comparison rules.
dv.equal(1, 2) = false
dv.equal(1, 1) = true
dv.clone(value)
Deep clone any Dataview value, including dates, arrays, and links.
dv.clone(1) = 1
dv.clone({ a: 1 }) = { a: 1 }
dv.parse(value)
Parse an arbitrary string object into a complex Dataview type (mainly supporting links, dates, and durations).
dv.parse("[[A]]") = Link { path: A }
dv.parse("2020-08-14") = DateTime { 2020-08-14 }
dv.parse("9 seconds") = Duration { 9 seconds }
File I/O
These utility methods are all contained in the dv.io
sub-API, and are all asynchronous (marked by ⌛).
⌛ dv.io.csv(path, [origin-file])
Load a CSV from the given path (a link or string). Relative paths will be resolved relative to the optional origin file (defaulting to the current file if not provided). Return a dataview array, each element containing an object of the CSV values; if the file does not exist, return undefined
.
await dv.io.csv("hello.csv") => [{ column1: ..., column2: ...}, ...]
⌛ dv.io.load(path, [origin-file])
Load the contents of the given path (a link or string) asynchronously. Relative paths will be resolved relative to the
optional origin file (defaulting to the current file if not provided). Returns the string contents of the file, or
undefined
if the file does not exist.
await dv.io.load("File") => "# File\nThis is an example file..."
dv.io.normalize(path, [origin-file])
Convert a relative link or path into an absolute path. If origin-file
is provided, then the resolution is doing as if
you were resolving the link from that file; if not, the path is resolved relative to the current file.
dv.io.normalize("Test") => "dataview/test/Test.md", if inside "dataview/test"
dv.io.normalize("Test", "dataview/test2/Index.md") => "dataview/test2/Test.md", irrespective of the current file
Query Evaluation
⌛ dv.query(source, [file, settings])
Execute a Dataview query and return the results as a structured return.
The return type of this function varies by the query type being executed,
though will always be an object with a type
denoting the return type. This version of query
returns a result type - you may want tryQuery
, which instead throws an error on failed query execution.
await dv.query("LIST FROM #tag") =>
{ successful: true, value: { type: "list", values: [value1, value2, ...] } }
await dv.query(`TABLE WITHOUT ID file.name, value FROM "path"`) =>
{ successful: true, value: { type: "table", headers: ["file.name", "value"], values: [["A", 1], ["B", 2]] } }
await dv.query("TASK WHERE due") =>
{ successful: true, value: { type: "task", values: [task1, task2, ...] } }
dv.query
accepts two additional, optional arguments:
1. file
: The file path to resolve the query from (in case of references to this
). Defaults to the current file.
2. settings
: Execution settings for running the query. This is largely an advanced use case (where I recommend you
directly check the API implementation to see all available options).
⌛ dv.tryQuery(source, [file, settings])
Exactly the same as dv.query
, but more convenient in short scripts as
execution failures will be raised as JavaScript exceptions instead of a
result type.
⌛ dv.queryMarkdown(source, [file], [settings])
Equivalent to dv.query()
, but returns rendered Markdown.
await dv.queryMarkdown("LIST FROM #tag") =>
{ successful: true, value: { "- [[Page 1]]\n- [[Page 2]]" } }
⌛ dv.tryQueryMarkdown(source, [file], [settings])
Exactly the same as dv.queryMarkdown()
, but throws an error on parse failure.
dv.tryEvaluate(expression, [context])
Evaluate an arbitrary dataview expression (like 2 + 2
or link("text")
or x * 9
); throws an Error
on parse or
evaluation failure. this
is an always-available implicit variable which refers to the current file.
dv.tryEvaluate("2 + 2") => 4
dv.tryEvaluate("x + 2", {x: 3}) => 5
dv.tryEvaluate("length(this.file.tasks)") => number of tasks in the current file
dv.evaluate(expression, [context])
Evaluate an arbitrary dataview expression (like 2 + 2
or link("text")
or x * 9
), returning a Result
object of
the result. You can unwrap the result type by checking result.successful
(and then fetching either result.value
or result.error
). If you want a simpler API that throws an error on a failed evaluation, use dv.tryEvaluate
.
dv.evaluate("2 + 2") => Successful { value: 4 }
dv.evaluate("2 +") => Failure { error: "Failed to parse ... " }