Using a note to store global properties to use in templater

The Goal

I have a template for a book note, in which, I want to have two properties of a book and author. On creation of the note I currently have a prompt that asks for the book name and the author and then I use that data to create the yaml.

Here is the code so far.

<%*	
if (title.startsWith('Untitled')) { 
		title = await tp.system.prompt('Title - '); 
		await tp.file.rename(`${title}`); 
}

let book = await tp.system.prompt("Book");
let author = await tp.system.prompt("Author");

async function camelCase(str) {
    // Using replace method with regEx
    return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function (word, index) {
        return index == 0 ? word.toLowerCase() : word.toUpperCase();
    }).replace(/\s+/g, '');
}
let camelBook = await camelCase(book);

-%>
<%"---"%>
type: bookNote
book: <%book%>
author: <%author%>
date: <%tp.date.now("MMMM D, Y")%>
<%"---"%>

>[!tags]
>#<%tag%>
>#<%camelBook%>

The problem

The above code worked and did what I needed it to but it was annoying to enter in the book name and author each time I created a new note. I wanted a system in place that would remember the last book and author that I had used and then I would only need to change the book name when I started reading a new book.

The solution

Step one - Storing the values

I created a new note called “Last book property” and in that note I have two properties. A book and a author.

	---
	book: Book I'm reading
	author: Author of book
	---

Step two - I needed to access the properties of the file

In order to find the file I used the find_tfile function where you just need to input the file name.

	let file = tp.file.find_tfile("Last book property");

Next I needed to be able to access the frontmatter which is where the files properties are stored. To do this I first found the metaDataCache and then retrieved the frontmatter from there.

	let cache = app.metadataCache.getFileCache(file);
	let frontMatter = cache.frontmatter;

After that I was able to get each of the properties.

	let bookProp = frontMatter.book;
	let authorProp = frontMatter.author;

Step 3 - Displaying the current book and author

Now that I had those properties it was a simple matter to get them displayed. The second parameter of the templater prompt allows you to show a default value. So now when creating a new note the current book will be displayed and I can just hit enter.

	let book = await tp.system.prompt("Book", bookProp);
	let author = await tp.system.prompt("Author", authorProp);

Step 4 - Changing the properties

So when I start reading a new book and enter the title into the prompt I’m going to want it to change the property in the “Last book property” file. This can’t be done from the cache frontmatter. To do I needed to call the function processFrontMatter instead, which takes a tFile, which I already had.

Then when I have access to the fm I check to see if the property is different from the result that I got from the system prompt. And then if it is different assign the property the new value, like this:

app.fileManager.processFrontMatter(file, fm => { 
		if (book != bookProp){
			fm['book'] = book;
		}
		if (author != authorProp){
			fm['author'] = author;
		}
})

Completed code

So I wanted to share this with everyone because when I was searching I couldn’t find an answer on how to do this so I needed to come up with a solution on my own. This same method could be used for storing any type of global property that you might need. Here is the final completed code for the template.

<%*
	let file = tp.file.find_tfile("Last book property");	
	let cache = app.metadataCache.getFileCache(file);
	let frontMatter = cache.frontmatter;
	let bookProp = frontMatter.book;
	let authorProp = frontMatter.author;

	

if (title.startsWith('Untitled')) { 
		title = await tp.system.prompt('Title - '); 
		await tp.file.rename(`${title}`); 
}

let book = await tp.system.prompt("Book", bookProp);
let author = await tp.system.prompt("Author", authorProp);
let tag = await tp.system.prompt("Tag");

async function camelCase(str) {
    // Using replace method with regEx
    return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function (word, index) {
        return index == 0 ? word.toLowerCase() : word.toUpperCase();
    }).replace(/\s+/g, '');
}

	let camelBook = await camelCase(book);

	// change frontmatter
	app.fileManager.processFrontMatter(file, fm => { 
		if (book != bookProp){
			fm['book'] = book;
		}
		if (author != authorProp){
			fm['author'] = author;
		}
	})
-%>
<%"---"%>
type: bookNote
book: <%book%>
author: <%author%>
date: <%tp.date.now("MMMM D, Y")%>
<%"---"%>

>[!Tags]
>#<%tag%>
>#<%camelBook%>

1 Like

Note there is an error in the above code. When copying it out I didn’t include where I was getting the file title from. This line should be added to the top.

let title = tp.file.title