Help combining templates, javascript If-Then and Suggester

First, search the help docs and this forum. Maybe your question has been answered! The debugging steps can help, too. Still stuck? Delete this line and proceed.

What I’m trying to do

I am new to javascript, and would love some help coding If-Then scenarios while utilizing the suggester function and calling appropriate templates. I know…it’s a lot.

I write reviews of bars and restaurants. Each bar/restaurant has its own master file within either the Bar folder or Restaurant folder that contains its name, the owner and the city.

When it’s time to write a review my goal is to:

  • Respond to a prompt: Bar or Restaurant
  • If Bar, see all files within the Bar folder so I can choose the appropriate business and likewise for Restaurants
  • Have the system pull up the relevant template (BarReview / RestaurantReview), and finally
  • Have the new template pull in data from the businesses’ master file - such as Chef, Owner, etc.

OK. That’s a lot. If anyone is willing to help out, I believe others might find this info useful as well. Thanks !!!

The Bar Template looks like:


<% reviewType %> Review
<% dateValue %>

<% barName %>
Their best drink is: <% bestDrink %>

Chef: I don’t know how to reference the Bar Master file here (though know to put “.Chef” after bracketed name to pull metadata)
Owner: SAME HERE

Notes:

Things I have tried

<%* 
let dateValue = tp.date.now() 
let reviewType = await tp.system.suggester(["Bar", "Restaurant"], ["Bar", "Restaurant"]) 
if (reviewType == "Bar") {
	let barName = await tp.system.suggester((item) => item.basename, app.vault.getMarkdownFiles().filter(file => file.path.startsWith("Bar Folder")
	let bestDrink = await tp.system.prompt("What is best drink?");
} else {
	let restaurantName = await tp.system.suggester((item) => item.basename, app.vault.getMarkdownFiles().filter(file => file.path.startsWith("Restaurant Folder")
	let bestMeal = await tp.system.prompt("What is best meal?");
}
-%> 

Sadly - this isn't working at all....
1 Like

What’s not working? At first glance it seems sensible enough, beside the fact you don’t actually output anything from your template block

Hey - thx for response. I’m now trying to break this up into smaller bits to make is easier for me to learn!

The following works perfectly - allowing me to filter files within a folder for the suggester function based on YAML data:

<%*
const dv = this.app.plugins.plugins[“dataview”].api;
let allProjects = dv.pages(‘“020 Investments/Uninvested Funds”’);
let chosenProjects = allProjects.where(p => p.bucket == “SP”).file.sort(n => n.name);
let suggestions = chosenProjects.name;
let values = chosenProjects.link;
-%>

<% await tp.system.suggester(suggestions,values) %>

WIth that working, the next step is to CHOOSE whether the YAML data = SP or LB and then filter along that key value. My code is as follows:

<%*
const dv = this.app.plugins.plugins[“dataview”].api;
const bucketID = await tp.system.suggester([“LB”, “SP”],[“LB”, “SP”]);
let allProjects = dv.pages(‘“020 Investments/Uninvested Funds”’);
if (bucketID == “LB”) {
let chosenProjects = allProjects.where(p => p.bucket == “LB”).file.sort(n => n.name);
} else {
let chosenProjects = allProjects.where(p => p.bucket == “SP”).file.sort(n => n.name);
}
let suggestions = chosenProjects.name;
let values = chosenProjects.link;
-%>

<% await tp.system.suggester(suggestions,values) %>

While this does prompt me to choose LB or SP, it then ceases to function. I’m guessing I’m missing something fairly basic…if you have any ideas, they are MUCH appreciated. Thanks.

Lets start with the bonus tip:

Bonus tip: How to present code properly in a forum post

If you want to showcase either markdown, or code blocks, or dataview queries properly in a forum post, be sure to add one line before and one life after what you want to present with four backticks, ````. This will ensure that any other backticks (like for code blocks or queries) is properly shown.

Applying this to you post gets this:

Hey - thx for response. I’m now trying to break this up into smaller bits to make is easier for me to learn!

The following works perfectly - allowing me to filter files within a folder for the suggester function based on YAML data:

<%*
const dv = this.app.plugins.plugins["dataview"].api;
let allProjects = dv.pages('"020 Investments/Uninvested Funds"');
let chosenProjects = allProjects.where(p => p.bucket == "SP").file.sort(n => n.name);
let suggestions = chosenProjects.name;
let values = chosenProjects.link;
-%>

<% await tp.system.suggester(suggestions,values) %>

WIth that working, the next step is to CHOOSE whether the YAML data = SP or LB and then filter along that key value. My code is as follows:

<%*
const dv = this.app.plugins.plugins["dataview"].api;
const bucketID = await tp.system.suggester(["LB", "SP"],["LB", "SP"]);
let allProjects = dv.pages('"020 Investments/Uninvested Funds"');
if (bucketID == "LB") {  
	let chosenProjects = allProjects.where(p => p.bucket == "LB").file.sort(n => n.name);
		} else {  
	let chosenProjects = allProjects.where(p => p.bucket == "SP").file.sort(n => n.name);
}
let suggestions = chosenProjects.name;
let values = chosenProjects.link;
-%>

<% await tp.system.suggester(suggestions,values) %>

While this does prompt me to choose LB or SP, it then ceases to function. I’m guessing I’m missing something fairly basic…if you have any ideas, they are MUCH appreciated. Thanks.

The main issue with your revised version is scoping, to be more precise variable scoping. You define let chosenProjects = ... within either of the blocks under the if statement. The value you assign to it there, is lost after you exit that particular block.

Put another way, somewhat simpliflied, if you declare a variable after an opening brace, {, it’s only valid until the corresponding closing brace, }.

To get around it, you should declare the variable in the outermost block where you need this variable. Two stripped down examples:

if ( bucketID == "LB") {
  let chosenProjects = "hi"
  // Until the next line, it's value is "hi"
} else {
  let chosenProjects = "bye"
  // This is a different variable, with value "bye" until the next line
}

// Here outside of the blocks, chosenProjects don't have a value
// and is unknown...

The code above is your current variant, and it’ll fail with no values for the last suggester. If on the other hand you moved the declaration _outside into that block, you’d get this:

let chosenProjects // Just the declarations, but it hasn't got a value
if ( bucketID == "LB" ) {
  chosenProjects = "hi"
} else {
  chosenProjects = "bye"
}

// Now chosenProjects would be either "hi" or "bye" depending
// on the value of "bucketID"

This small change of adding let chosenProjects before the if-statement, and removing the let within the blocks within it, should make your query work again.

Some possible other changes

Here are some other suggestions related to your template:

  • Using the suggester, you don’t need to repeat the array of choices, you can also do await tp.system.suggester(t => t, ["LB", "SP"]) where we’re using a dynamic function to say that the presentation suggestions are the same as the value list.
  • It’s possible to bail out of the suggester, leaving an empty value for bucketID. This you should warn the end user about, and possibly exit your template insertion on.
  • It’s a good thing not to repeat code, so when the chosenProject settings only varies by the bucketID, there is no need to actually duplicate that query, and you could just use the bucketID within the WHERE clause directly
  • Sometimes, but this is definitively a matter of personal preference, using a variable just one time could be avoided by just using it declaration value directly
  • To increase readability I tend to write those daisy chained queries with (almost) every new “dot-function” on its own line indented with two spaces.

Doing all of this with your script, I end up with the following template:

<%*
const dv = this.app.plugins.plugins["dataview"].api

const bucketID = await tp.system.suggester(t => t, ["LB", "SP"]);
const allProjects = dv.pages('"020 Investments/Uninvested Funds"')

if ( !bucketID ) {
  window.alert("No project was chosen! Expect anomalies")
  return
}

const chosenProjects = allProjects
  .where( p => p.bucket == bucketID )
  .file
  .sort( f => f.name )
_%>

<% await tp.system.suggester(chosenProjects.name, chosenProjects.link) %>

It should perform the same, and there are some degree of preference in there, but I just wanted to present it to you for comparison.

2 Likes

Oh my gosh. Not only does that work, but I learned so much from your explanation. I can’t thank you enough - this is an Obsidian-Life-Changing type of learning so thank you, thank you, thank you !

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