Templater icon indicating copy to clipboard operation
Templater copied to clipboard

Racecondition between "Create new note from template" and "Folder Template Configuration"

Open dredhorse opened this issue 3 years ago • 9 comments

this might be in issue only in certain configuration (aka mine).

First template: check for untitled ask for title await tp.file.rename(title); ask questions include second template

Second template: ask more questions.

folders are configured with using first template as folder template

create a new note from template with the folder template (or really any other) you see the dialogue but you also see the same dialogue in the background... templater is running 2 times, one time triggered by create new note and one time triggered by creating a new file in a folder associated with a template.

Solution: if you create a new note from template, stop processing of folder templates

dredhorse avatar Jul 31 '22 18:07 dredhorse

Can you give me an example vault to repro with?

AB1908 avatar Aug 26 '22 21:08 AB1908

did send you a link to a copy of my vault. just try to create a note in 600 or so... so click on 600, cmd+p, templater: new note from template, _NewNote

dredhorse avatar Aug 29 '22 13:08 dredhorse

did you take a look at this? I guess I will disable templater for / atm to get around this issue. But I noticed that in the current version it is more "stable". I can go through the full creation process of the new note from template. But after I'm done I need to escape the "underlying" second "process". If needed I can do a video.. and share the _NewNote and the t_note template.

MMoMM-org avatar Nov 14 '22 14:11 MMoMM-org

Might've lost it. Will check later in the week.

AB1908 avatar Nov 14 '22 19:11 AB1908

I am having a similar issue. I have a default template containing this:

<%*
  let title = tp.file.title
  if (title.startsWith("Untitled")) {
    title = await tp.system.prompt("Title");
    await tp.file.rename(title);
  } 
-%>
---
title:  <%* tR += title %>
created: <% tp.date.now() %>
---

<%tp.file.cursor(1)%>

Then, if I run "Create new note from template" I don't expect the default template being triggered, but in practice it is being triggered.

So, let's say I have a second template with this content:

<%* let title = await tp.user.ensure_title(tp) -%>
# <%* tR += title %>

The user script looks like this:

module.exports = async function (tp) {
    let title = tp.file.title
    if (title.startsWith("Untitled")) {
        title = await tp.system.prompt("Title");
        await tp.file.rename(title);
    }
    return title;
}

If I now call 'create file from template' using the second template as argument, I get a prompt twice, One coming from the default template, and the final one coming from my second template. The result is a correctly generated page, but I'm wondering why is the default template being triggered. Default template means that I have it setup to run when a note in the folder / is created.

danielo515 avatar Aug 10 '23 14:08 danielo515

Have you tried to use a lockTemplateCreation (or whatever you want to name it) field attached to the tp object in the script?

You could then use it to check for it in every template as a first action and skip anything if true or equals a certain value: conditional templating is your friend.

stef-rausch avatar Aug 11 '23 14:08 stef-rausch

There is an alternative if you are willing to install another plugin.

With CustomJS, you can define a class which can be loaded. The plugin creates an instance that can be used anywhere where JavaScript can be used, e.g., within a Templater script.

This solution is “clean” and future-proof.

stef-rausch avatar Aug 11 '23 16:08 stef-rausch

CustomJS class:

// user.script.custom.template-lock.js - version 0.0.1+20230811
// license: MIT - Copyright (c) 2023 Stefano F. Rausch <[email protected]>

class Template {
    static #lock = false

    static get lock() {
        return Template.#lock
    }

    static set lock(boolean = true) {
        return Template.#lock = boolean === true
    }
}

Templater script start:

<%_*

const {Template: template} = customJS

if (!template.lock) {
    template.lock = true

_%>

Your template goes here:

TEMPLATE

Templater script end:

<%-*
}

template.lock = false

-%>

I had no Templater race conditions -- and in some cases, duplicate files in different folders -- after using this approach.

stef-rausch avatar Aug 11 '23 19:08 stef-rausch

danielo515 correctly asked separately if Templater cannot be used to achieve the same Template.lock results shown above.

Sure: with a user function returning a class object you stay within the Templater playground.

stef-rausch avatar Aug 11 '23 21:08 stef-rausch