Creating Forms with Dependent Dataview Fields
This guide provides a step-by-step approach to creating forms where dataview fields depend on previous form values to select different result sets.
Prerequisites
- Modal Form plugin installed
- Dataview plugin installed and enabled
- Optionally Templater plugin installed for triggering the form and create new notes
Step 1: Understanding the Basics
First, let's understand how the Modal Form plugin works with Dataview:
- Modal Form allows you to create forms with various field types
- Dataview fields can query your vault data dynamically
- Form values can be accessed using the
form
variable in dataview queries - Changes to form fields automatically trigger updates to dependent dataview fields
Step 2: Creating a Basic Form Structure
To create a form with dependent fields, start by creating a new form in the form manager. For this guide, we'll create a form named dependent-books-test
which we'll reference in later steps.
Step 3: Adding Primary Selection Fields
Add fields that will influence subsequent dataview queries:
For the genre field, use a dataview query to get all unique genres:
dv.pages("#book").genre.distinct().sort()
For the rating slider, set appropriate min and max values:
{
"min": 1,
"max": 5
}
Step 4: Adding Dependent Dataview Fields
Now add fields that depend on the values selected in the previous fields:
For the author field, filter by the selected genre:
dv.pages("#book")
.where(p => p.genre == form.genre)
.author.distinct().sort()
For the series field, filter by both genre and author:
dv.pages("#book")
.where(p => p.genre == form.genre && p.author == form.author)
.series.distinct().sort()
Step 5: Adding a Preview Block
Add a markdown block to show a preview based on the current selections:
Use this query to display matching books:
return dv.pages("#book")
.where(p =>
p.genre == form.genre &&
p.rating >= form.minRating &&
(form.author ? p.author == form.author : true) &&
(form.series ? p.series == form.series : true)
)
.sort(p => p.rating, "desc")
.limit(5)
.map(p => `- ${p.file.link} (${p.rating}⭐)`)
.join("\n")
Step 6: Adding a Book Selection Field
Add a field to select a specific book based on all previous selections:
dv.pages("#book")
.where(p =>
p.genre == form.genre &&
p.rating >= form.minRating &&
(form.author ? p.author == form.author : true) &&
(form.series ? p.series == form.series : true)
)
.sort(p => p.rating, "desc")
.file.name
Step 7: Using the Form in a Template
Create a template to use your form:
<%*
const result = await MF.openForm('dependent-books-test');
if (result.status === "ok") {
// Generate note content based on form results
tR += `# ${result.fields.selectedBook}\n\n`;
tR += `## Reading Status\n\n`;
tR += `Current status: Reading\n`;
tR += `Rating: ${result.fields.minRating}⭐\n\n`;
tR += `## Book Details\n\n`;
tR += `- **Author**: ${result.fields.author}\n`;
tR += `- **Genre**: ${result.fields.genre}\n`;
if (result.fields.series) {
tR += `- **Series**: ${result.fields.series}\n`;
}
tR += `\n\n## Notes\n\n`;
} else {
tR += "Form was cancelled";
}
%>
Step 8: Error Handling for Dependent Fields
When working with dependent fields, it's recommended to handle cases where previous fields haven't been filled yet. Here's one example of how to modify your queries to handle these cases:
For the author field:
form.genre ? dv.pages("#book")
.where(p => p.genre == form.genre)
.author.distinct().sort() : []
For the series field:
form.genre && form.author ? dv.pages("#book")
.where(p => p.genre == form.genre && p.author == form.author)
.series.distinct().sort() : []
For the book selection field:
form.genre ? dv.pages("#book")
.where(p =>
p.genre == form.genre &&
p.rating >= form.minRating &&
(form.author ? p.author == form.author : true) &&
(form.series ? p.series == form.series : true)
)
.sort(p => p.rating, "desc")
.file.name : []
Step 9: Adding Multi-select Dependent Fields
For more complex scenarios, you can use multi-select fields with dependencies:
dv.pages("#book")
.where(p => p.genre == form.genre)
.file.tags
.flatMap(t => t)
.distinct()
.sort()
Step 10: Saving and Using Your Form
- Save your template in the Obsidian vault
- Create a button, command or hotkey to trigger the template
- When the template is triggered, it will open the form and create a new note with the selected data
Tips
- Cascading Dependencies: You can create multiple levels of dependencies (genre → author → series → book)
- Error Handling: Always check if form fields exist before using them in queries
- Real-time Updates: Form data is automatically synchronized with your queries