New Properties and templater prompts and commands?

@Schollert add this to any template to change a single field(s):

<%*
setTimeout(() => {
  app.fileManager.processFrontMatter(tp.config.target_file, frontmatter => {

    // Update or add as many fields as you want
    frontmatter['Some property'] = 'Some value'
    frontmatter['Another property'] = 'Some other value'

    // You can even remove properties if you want
    delete frontmatter['Unwanted property']

  })
}, 200) // the reason for the timeout is to let the template complete first
-%>

No need to re-think your template design.

23 Likes

Wow - cool! Thank you very much!!

1 Like

Spent the better part of yesterday down the rabbit hole of frontmatter and Templater and MetaEdit and all sorts of other things trying to do something that, in theory, should have been really simple.

Of course I came across this at the end instead of the beginning…

Not entirely a waste - ended up writing a JS function to parse geo data from Google Places into address/street/province/description frontmatter fields and then insert a Leaflet map. Once I came across your post it was a five minute bolt up.

Could have asked I suppose but the spelunking is half the fun.

Much appreciated!

2 Likes

Just a small/final update from my side. With your input I managed to get my template to ask for title and two tags (category and subject) and place the information correct. Great fun fiddling with it to understand how things work.

I leave the code here, in case other want to so something similar.

<%* 
let title = tp.file.title 
let sSubject = ""
let sCategory = ""

if (title.startsWith("Untitled")) { 
  title = await tp.system.prompt("Title"); 
} await tp.file.rename(title);

sCategory = await tp.system.prompt("Category");
sSubject = await tp.system.prompt("Subject");

setTimeout(() => {
  app.fileManager.processFrontMatter(tp.config.target_file, frontmatter => {
  frontmatter["category"] = sCategory;
  frontmatter["subject"] = sSubject;
  })
}, 200)

-%>
9 Likes

I do the following:

---
KEYs: VALUEs for the template
---

<%_* tR += "" _%>

---
KEYs: VALUEs for the new note based on the template
---

CONTENT

The <%_* tR += "" _%> deletes everything collected until that point of execution.

Nicely formatted and easier to write. :wink:

Hey, Alan,

Last time I incorporated your solution in a longer Templater Js script and it threw the usual merging issues pop-up on me (and added false field values as well, ostensibly because of timing issues in my script).
Used the MetaEdit way instead:

// Using the MetaEdit API's createYamlProperty function add the 'class' property with the value 'dg_uploaded'
const { createYamlProperty } = this.app.plugins.plugins["metaedit"].api;
const classPropertyName = 'class';
await createYamlProperty(classPropertyName, 'dg_uploaded', currentFile);
console.log("Added 'class' property with value 'dg_uploaded' in the current file.");

If anybody wants to use this, let me remind them that currently adding only a single property works reliably in MetaEdit. (See here.)

EDIT. Turns out this doesn’t work very well, either. Dang, these timing issues and then messing up and correcting YAML keys and values really cut into my days…

EDIT 2.
If adding single or multiple properties draws errors (because everybody’s scripts are different and note lengths can vary, not to mention CPU speed differences or other quirks), one very strange-sounding workaround would be to batch-create a dummy_key: dummy field line (or two) in every file using an outside of Obsidian search and replace method (like the one discussed here), then in the templater script we search and replace those dummies on demand, like so:

  // Replace some fields
  updatedContent = updatedContent.replace(/dg_upload_status:\sdown/g, 'class: dg_uploaded');
  updatedContent = updatedContent.replace(/unformatted⚪/g, 'formatted🟢');
2 Likes

this is great - thank you!

1 Like

Hi, thanks for that but… I have tried changing only one property called Parent and it has eliminated the rest of the property as well as everything that that template has in addition

This is my code:

<%*
  app.fileManager.processFrontMatter(tp.config.target_file, frontmatter => {

    // Update or add as many fields as you want
   frontmatter['father'] = 'hi'

  })

-%>

Thanks!!!

I’ve been using Zachatoo’s “Update frontmatter” snippet tailored to my need without any issue of this kind so far :thinking:

Maybe you could try something like:

<%*
const file = tp.file.find_tfile(tp.file.path(true));
await app.fileManager.processFrontMatter(file, (frontmatter) => {
  // Update or create key "father"
  frontmatter["father"] = "Hi!";
  // Update or create key "son"
  frontmatter["son"] = "Hey there...";
  // Delete key "mother" (if present)
  delete frontmatter["mother"];
})
-%>

I’ve tested this on a note with the following content:

---
father: 
mother:
---
## Lorem Ipsum

> "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..."
> "There is no one who loves pain itself, who seeks after it and wants to have it, simply because it is pain..."

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum efficitur vel magna nec rutrum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam ac nibh nec eros sollicitudin viverra. Sed porttitor pretium molestie. Integer viverra turpis orci, et semper justo tempus sed. Sed non porta lorem, sed venenatis elit. Proin diam dui, pulvinar vitae egestas ac, dictum a magna. Praesent tincidunt augue vel nunc aliquam, eu pharetra diam finibus. In placerat est ut lorem dignissim commodo. Aenean vulputate lectus a dapibus tincidunt.

Aenean at condimentum neque, ullamcorper efficitur dui. Integer lacinia arcu ac rhoncus convallis. Morbi nunc lacus, ullamcorper at hendrerit at, ultrices in nisi. Ut elementum dignissim condimentum. Curabitur tortor est, molestie non accumsan vitae, congue ut ex. Aenean sed nibh enim. Maecenas eu eros commodo, volutpat quam nec, pharetra odio. Suspendisse imperdiet aliquet dolor, a faucibus nisi varius vel. Ut molestie dapibus lobortis. Fusce quis dui elit. Vivamus rutrum iaculis sagittis. Etiam venenatis felis ut mauris egestas, sit amet dictum eros rhoncus. Suspendisse eget magna quis magna accumsan maximus eget vel ipsum. Fusce dictum faucibus neque, eu pharetra sem sagittis ornare.

and ended up with:

---
father: Hi!
son: Hey there...
---
## Lorem Ipsum

> "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..."
> "There is no one who loves pain itself, who seeks after it and wants to have it, simply because it is pain..."

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum efficitur vel magna nec rutrum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam ac nibh nec eros sollicitudin viverra. Sed porttitor pretium molestie. Integer viverra turpis orci, et semper justo tempus sed. Sed non porta lorem, sed venenatis elit. Proin diam dui, pulvinar vitae egestas ac, dictum a magna. Praesent tincidunt augue vel nunc aliquam, eu pharetra diam finibus. In placerat est ut lorem dignissim commodo. Aenean vulputate lectus a dapibus tincidunt.

Aenean at condimentum neque, ullamcorper efficitur dui. Integer lacinia arcu ac rhoncus convallis. Morbi nunc lacus, ullamcorper at hendrerit at, ultrices in nisi. Ut elementum dignissim condimentum. Curabitur tortor est, molestie non accumsan vitae, congue ut ex. Aenean sed nibh enim. Maecenas eu eros commodo, volutpat quam nec, pharetra odio. Suspendisse imperdiet aliquet dolor, a faucibus nisi varius vel. Ut molestie dapibus lobortis. Fusce quis dui elit. Vivamus rutrum iaculis sagittis. Etiam venenatis felis ut mauris egestas, sit amet dictum eros rhoncus. Suspendisse eget magna quis magna accumsan maximus eget vel ipsum. Fusce dictum faucibus neque, eu pharetra sem sagittis ornare.

Update key

1 Like

Thanks but… this is my result:
CleanShot-2024-01-05-at-08.25.42

Could it be something in the configuration or what could be happening to make Obsidian act like this?

Thank you very much again

Processing the frontmatter of the current file can be icky, and is usually best done using a setTimeout() call to processFrontMatter(), this to avoid race conditions on who edits the file: You, the template or processFrontMatter().

I’m on mobile now, but there are multiple examples here in the forum for the syntax.

Thanks but… same problem :sob:

<%*
const file = tp.file.find_tfile(tp.file.path(true));

setTimeout(() => { 
app.fileManager.processFrontMatter(file, (frontmatter) => {
  // Update or create key "father"
  frontmatter["father"] = "Hi!";
  // Update or create key "son"
  frontmatter["son"] = "Hey there...";
  // Delete key "mother" (if present)
  delete frontmatter["mother"];
}) }, 200)
-%>

I see something strange, if I write something in the new note before applying the template then what I have in the template appears but the parameters I have in the template no longer pass as parameters but as text.

CleanShot-2024-01-05-at-08.25.42

When you insert a template into an already existing file, you can’t use the triple-dash fences around new properties. You’ll need to use the processFrontMatter() method, and when dealing with the current file remember to use the setTimeout() as described earlier.

Other than that, it comes down to knowing how to code and pass variables around in your script. If you don’t know that, you’ll need some basic learning of javascript first.

1 Like

thanks, but I have not used triple-dash at any time.

I just put HELLO before applying the template to the new note and it made that so strange. I did it so that the result could be seen.

If, for example, after applying the template and deleting everything except what is in the code, press crtl+z and my original template appears without the parameter data that we have passed to it by code :upside_down_face:

If anyone can tell me a solution to what my obsidian is doing to me, I would greatly appreciate it.

Good day!

With triple-dash I mean the code fence / text in front and after the frontmatter, aka ---. In your last screen shot, you already have a frontmatter with triple-dashes around the father and son property. You then proceed to insert the plantilla Favorito template, which also has a frontmatter, and it inserts the template just as you asked for with another set of triple-dashes.

Instead of inserting that text, from plantilla Favorito, after the frontmatter which already exists, you should have updated the frontmatter using the processFrontMatter() method, and do stuff like:

frontmatter["Padre"] = '"[[Listado de Plantillas]]"'

(Possibly with another syntax to ensure the correct formatting of links. Not sure how they’re treated within processFrontMatter() as I haven’t tested that part)


In other words, when you insert the plantilla Favorito template, it does just what it is asked to do, and that is insert any text from that template at the current cursor location, and execute any template command blocks as it encounters them. In this case it’ll update the father and son part of the frontmatter after a slight delay of 200ms. Just as expected.

1 Like

This is wonderful AlanG, thank you very much! :slight_smile:

I have two suggestions for improvement or enhancement, but unfortunately my JS skills are not sufficient to do this myself:

  • Do you know how to add property-keys to already existing ones and not overwriting them?
  • The disadvantage of using templater templates is, that updating properties in the property pane won’t update templater templates. A workaround of this disadvantage could be, to include normal templates (which will be updated) through templater scripts. … I think there is the function tp.file.include(), which is probably meant for that, but I didn’t manage to get this working… :confused:

Thanks a lot in advance! :slight_smile:

The last part of the code in this post could help you.
I’m using the multi-line YAML key value convention Obsidian expects since the introduction of Properties (you can also set in Linter’s YAML section which key values you want to be multi-line) and the script is working well enough for me to use it as boilerplate now). I expect if you change tags with another key name, it will work too.

1 Like

Hi gino_m,

wow thanks!!! :slight_smile:

Using ChatGPT, I understood that if have to use that snippet of your code:

<%*
// Check if the 'Englishtexttranslated' tag exists before adding it
setTimeout(() => {
  app.fileManager.processFrontMatter(tp.config.target_file, frontmatter => {
    if (!frontmatter['tags'] || !frontmatter['tags'].includes('Englishtexttranslated')) {
      const tagsArray = Array.isArray(frontmatter['tags']) ? frontmatter['tags'] : [];
      if (!tagsArray.includes('Englishtexttranslated')) {
        tagsArray.push('Englishtexttranslated');
        frontmatter['tags'] = tagsArray;
      }
    }
  });
}, 350); // Timeout to allow preceding clipboard operations to complete
_%>

and change “tags” to any key I want and change “Englishtexttranslated” to any value I want to add.

If I want to have more properties added, I have to copy that part of the snippet:

	if (!frontmatter['tags'] || !frontmatter['tags'].includes('Englishtexttranslated')) {
	  const tagsArray = Array.isArray(frontmatter['tags']) ? frontmatter['tags'] : [];
	  if (!tagsArray.includes('Englishtexttranslated')) {
		tagsArray.push('Englishtexttranslated');
		frontmatter['tags'] = tagsArray;
	  }
	}

Thanks a lot gino! :slight_smile:

2 Likes

That’s pretty much what I do as a non-coder; take something that works and re-use it.

My recent efforts came with some issues that I first didn’t entirely understand, then since using timeouts and a large value (say, 2000ms) seems to have sorted out my issues.

As I understand it, Obsidian doesn’t like to have your properties modified while it is in the process of loading the metadatacache + backlinks (+ outlinks). So if I enter a huge file (say, more than 35kbs), I should need to wait to have things settle a bit or effect the changes with a delay.

1 Like