How to update a property's value in a Templater script?

What I’m trying to do

I’d like to update (existing) properties in a Templater script.

Things I have tried

Currently, I manually create the frontmatter as shown in the example below.
I find it’s very limited as it’s just a creation of properties…


Is there a way to access a property value in a Templater script?


<%*  
	// Get project name
	const project_name = await tp.system.prompt("What's your project name?")
	
        // Set the current timestamp as the filename
	const new_title = "title_prefix" + project_name ;
	await tp.file.rename(new_title);
	
	// Move it to the project folder in the Projects folder
	const target_path = "Projects/" + project_name + "/" + new_title
	await tp.file.move(target_path);  // folder created
-%>
---
other_properties: Not Shown in this Example
aliases: 
  - <% project_name %>
tags:
---

tp.frontmatter.<property_key_wo_space> returns the value of the property.
However, I still don’t know how to update the value…

I’m thinking to get the index of “aliases:” in the file content and add <% - ${project_name} %> to the next line. This assumes “aliases:” to be unique in the file.
For example, (conceptually…; not runnable;)

<%*
	const file_content_container = tp.file.content
	let content = file_content_container.split("\n");
	let index = content.findIndex(line => line.includes("aliases"));
-%>
index: <% index %>

Any ideas?

Try the Metaedit plugin, it provides metadata editing API.

Thanks for your suggestion.

I have tried the Metaedit.
It works for already existing file contents. Simply put, it ‘edits’ the contents.

However, in my understanding, Templater does not write file contents before terminating the script.
So, in my case, there’s no existing property to update in the target file.

It’s still limited to only creations, but,
can Metaedit also ‘create’ a new property of a file?
(Please assume that the target file has no content at all…)

These statements goes against each other. If you create a new file, and your template is applied there are no existing properties. Period. You can define properties to be inserted into that file after the template is applied, and if you want you can ask for stuff using a suggester which later on is inserted into your properties.

So I’m not sure what you define as “very limited”, and what you want to update from your template.

Upon playing with some Templater scripts, I’ve learned that I provided such invalid statements/descriptions, haha… Thanks for your help!


I initially thought Obsidian creates a file of the template and then runs the Templater code line by line in order.
For example,

---
status: <% await tp.system.suggester(["1","2"], ["1","2"], true, "input status") %>
---
<%*
new Notice(`status: ${tp.frontmatter.status}`);
-%>

I expected to see “status: 1” or “status: 2” because I thought status was already defined at the point of the notification. But, obviously, it was not the case; the noti message was “status: Undefined” in the notification.

Besides, I wanted to put the frontmatter at the top of the template, just like the example.
If do so, I can set a metadata value using the suggester or the prompt. However, in this way, I couldn’t “modify” the value, as far as I know.
Now that I think about it… If I put the frontmatter below an adequate Templater code block, the issue can be addressed; Simply, place the variable upon the modifications (e.g. status: <% project_name_modified %>).

Slightly off-topic but I didn’t want to put this in a separate share and showcase thread. Might benefit some people.

With Templater js code we can do some search and replace on the current file’s content and bind it to a hotkey.
E.g.:

<%*
const currentFile = app.workspace.getActiveFile();
if (!currentFile) return;
const fileContent = await app.vault.read(currentFile);

updatedContent = fileContent.replace(/(dg-publish: )true/g, `$1false`);
updatedContent = updatedContent.replace(/(share: )true/g, `$1false`);
updatedContent = updatedContent.replace(/formatlooksokayonsmallerfiles/g, 'formatted🟢');
updatedContent = updatedContent.replace(/unformatted⚪/g, 'formatted🟢');

await app.vault.modify(currentFile, updatedContent);

this.app.workspace.activeLeaf.view.editor.setCursor({line: 99999, ch: 0});
tR += "\n\n%%State your reason for making these changes.%%"
-%>

I’m using this to update or change some property values in files I decided to not publish. Two fields are set to false from true ($1 is a substitution for the bracketed part on the match side), and I update a tag field (it doesn’t matter if the field is non-existent in the current file; it will be replaced only if either of those exist).

One can easily replace some of these lines with one’s own values. The first three lines and the await.app. line must stay as they are. The three updatedContent = updatedContent.… lines can be deleted if you want to update only one thing.

The last two lines of code puts a predefined commented out text on the last line. If you dig that. If not, you can delete those.

I’m just going to leave Zachatoo’s Update frontmatter snippet → here :blush:
(In case it could be useful to someone :blush: … As it has been pretty useful to me :smile: )

3 Likes

This should be the accepted solution.

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