Unexpected behavior when using hooks.on_all_templates_executed on a blank file
- OS: Windows 11
- Templater version: 2.1.2
- Obsidian version: 1.5.3
- Templater settings: default settings with templates folder set to /templates/
Describe the bug When using the hooks.on_all_templates_executed callback like in the documentation with some text that should get added to the note before the frontmatter is updated:
<%*
tp.hooks.on_all_templates_executed(async () => {
const file = tp.file.find_tfile(tp.file.path(true));
await app.fileManager.processFrontMatter(file, (frontmatter) => {
frontmatter["key"] = "value";
});
});
%>
TEXT THAT SHOULD STAY
if the note the template is added to is blank (no text, no frontmatter), the text gets added and then removed when the frontmatter is added. By just adding a single character to the note before executing the template, both the text and frontmatter gets added without problem. (There is a pop-up "error" that the file has been modified externally and that it's merging the changes, not sure if that's an issue but you asked about it on discord)
Expected behavior The text and frontmatter should get added to the note even if the note is completely empty.
Additional context I've tried running the template above on two windows 11 computers with the same result, and also tried it in a new empty vault with only templater installed. I'm not 100% sure, but I believe that it worked as expected before, since I have a few templates that rely on this method. I don't use them regularly though, and I updated them to use this method last time I needed to use them (when the hook had just gotten added), so it's possible that I'm misremembering or that the notes I tested them on weren't completely empty.
I believe I've fixed this in the latest release, can you verify on your end?
Yes! It works now, thanks!
I'm actually still experiencing this issue. I'm on the latest version of templater.
My templates are structured like this:
I've tried to isolate the situations that it occurs in and this is what I've found:
Scenario 1: If I "Create new note from template" and I rely upon the "on_all_templates_executed" hook, I get an error "no such file or directory". This is obviously due to me using templater to move the file.
Should the hook handle that scenario?
My workaround for this scenario is to wrap the entire command within a setTimeout, and even with a 0 as the timeout it all works as expected.
Scenario 2: If I "Insert template" into a blank document the template is overwritten with nothing but the properties. Even using a super simple text using the exact example from the docs produces the same result. If you add a single character to the note before inserting the template, everything works as expected. If you add a really large setTimeout it bypasses the issue too.
Thanks,
@hjone72
Scenario 1:
How are you moving the file? Is it in one of the templates you're including? If you're moving in a tp.hooks.on_all_templates_executed function, there's no guarantee on the ordering of those functions.
Regardless, I have added a 1ms delay to make it less likely for this to happen.
Scenario 2: Can you provide a minimum reproducible example that I can test with to make a fix for this?
I am still experiencing this bug as well. Obsidian 1.5.8, Templater 2.2.3
This template overrides the text for me if inserted into an empty file
Line 1
Line 2
Line 3
Line 4
Line 5
<%*
tp.hooks.on_all_templates_executed(async () => {
const file = tp.file.find_tfile(tp.file.path(true));
await app.fileManager.processFrontMatter(file, (frontmatter) => {
frontmatter["key"] = Math.random();
});
});
%>
If a delay is added with await new Promise(resolve => setTimeout(resolve, 3000)) then the template works. I'd guess it's because Obsidian hasn't saved the changes to the file yet, and so considers it an empty file for the time being.
The issue is back for me as well, when I try to run the same example template as I posted earlier the text once again disappears once the properties have been added.
obsidian version 1.5.12, templater version 2.2.3
I can also reproduce this issue.
Obsidian: 1.5.12 Installer: 1.5.12 Templater: 2.2.3
Steps to reproduce:
- Apply a template to a blank note using the "Open insert template modal"
- The note must only have one line! If you add more lines, the issue disappears.
- The template must include content and
tp.hooks.on_all_templates_executedwith some application ofapp.fileManager.processFrontMatter.
Minimal example template:
## Attendees
- John
- Hendrik
-
## Agenda
- CallGate
<%*
tp.hooks.on_all_templates_executed(async () => {
const file = tp.file.find_tfile(tp.file.path(true));
await app.fileManager.processFrontMatter(file, (frontmatter) => {
frontmatter["status"] = "In progress"; // create a new property or update an existing one by name
frontmatter["Title"] = "New title";
});
});
-%>
Demo:
The "Note.md was modified externally, merging changes automatically" notice does not appear when the issue occurs. When it does, the issue does not occur, as far as I can tell. If you add more than the one aforementioned line, this notice appears, and the note content is not overwritten!
Thank you all, I can reproduce this issue and am investigating. I know exactly what line of code I can add to resolve this issue, however it would cause a regression for another issue #1253. I am investigating how I can resolve both of these issues.
Should be fixed in 2.2.4!
I'm seeing some very unpredictable behaviour with this change.
EDIT: I've isolated it down to a race condition while saving a file and creating a new one at the same time. (See image below)
The weird part is, once this error occurs Obsidian never recovers. You must reload the app and then everything will work again, until the race condition is triggered and the error occurs.
If I revert back to the previous version of Templater or remove the line await app.vault.append(active_editor.file, ""); then everything works again.
Should be fixed in 2.3.0, thanks @johnfromoptus !
| Obsidian | OS | plugin1 |
|---|---|---|
| 1.5.12 | Win 10 x64 pro (french) 22H2 | v2.3.1 |
Hi,
It still happens in 2.3.1 when using open insert template modal on an empty file.
Here is a template. The only workaround is to replace hook by setTimeout() with a delay of about 4000 on my system. If less than 1000, bug occurs for sure.
<%*
/* Be sure to switch to edit mode first (live preview)
It is required so it can insert the template in existing file. */
tp.user.Switch_to_edit_mode();
// start of template construct
let title = tp.file.title;
// tags are type of list and are expressed as array
const defTag = ["Obsidian/Plugin"];
if (title.startsWith("Untitled")) {
title = await tp.system.prompt("What is the plugin name ?");
await tp.file.rename(title);
}
let repo = await tp.system.prompt("What is the plugin repo URL ?");
setTimeout(() => {
app.fileManager.processFrontMatter(tp.config.target_file, frontmatter => {
frontmatter["tags"] = defTag;
frontmatter["repo"] = repo;
frontmatter["type"] = "plugin";
})
}, 500) // increase this timeout until the bug goes away
await tp.file.move("Categories/Tutos/Obsidian/Plugins/" + title);
%>
# Description
<% tp.file.cursor(1) %><%* app.workspace.activeLeaf.view.editor?.focus(); %>
# My use
# Shortkeys
| Shortkeys | Actions |
| --------- | ------- |
| | |
| | |
If use this script version using hook with command create new note from template, I get the opposite: the template content is inserted but not the properties.
<%*
/* Be sure to switch to edit mode first (live preview)
It is required so it can insert the template in existing file. */
tp.user.Switch_to_edit_mode();
// start of template construct
let title = tp.file.title;
// tags are type of list and are expressed as array
const defTag = ["Obsidian/Plugin"];
if (title.startsWith("Untitled")) {
title = await tp.system.prompt("What is the plugin name ?");
await tp.file.rename(title);
}
//don’t insert the title as a tag because it can be long and contains space
//defTag.push(title)
let repo = await tp.system.prompt("What is the plugin repo URL ?");
tp.hooks.on_all_templates_executed(async () => {
const file = tp.file.find_tfile(tp.file.path(true));
await app.fileManager.processFrontMatter(file, (frontmatter) => {
frontmatter["tags"] = defTag;
frontmatter["repo"] = repo;
frontmatter["type"] = "plugin";
});
});
/* setTimeout(() => {
app.fileManager.processFrontMatter(tp.config.target_file, frontmatter => {
frontmatter["tags"] = defTag;
frontmatter["repo"] = repo;
frontmatter["type"] = "plugin";
})
}, 500) */ // this timeout will prevent a bug when insert the template to an existing file that content only one empty line. When it happens, the note content is deleted. See: https://github.com/SilentVoid13/Templater/issues/1309#issuecomment-2079178033
await tp.file.move("Categories/Tutos/Obsidian/Plugins/" + title);
%>
@Fred-Vatin I tested your template (with the userscript part removed), and got the same result when inserting into a blank file: The content was lost, and the frontmatter changes stayed. The file was moved as expected.
When I compared your problematic template to my working ones, the main difference was that you had the prompts and renaming outside tp.hooks. If I put all the prompts and such that you have inside tp.hooks.on_all_templates_executed, the content of the note is not lost anymore. I changed it like so:
<%*
tp.hooks.on_all_templates_executed(async () => {
// start of template construct
let title = tp.file.title;
// tags are type of list and are expressed as array
const defTag = ["Obsidian/Plugin"];
if (title.startsWith("Untitled")) {
title = await tp.system.prompt("What is the plugin name ?");
await tp.file.rename(title);
}
//don’t insert the title as a tag because it can be long and contains space
//defTag.push(title)
let repo = await tp.system.prompt("What is the plugin repo URL ?");
const file = tp.file.find_tfile(tp.file.path(true));
await app.fileManager.processFrontMatter(file, (frontmatter) => {
frontmatter["tags"] = defTag;
frontmatter["repo"] = repo;
frontmatter["type"] = "plugin";
});
});
/* setTimeout(() => {
app.fileManager.processFrontMatter(tp.config.target_file, frontmatter => {
frontmatter["tags"] = defTag;
frontmatter["repo"] = repo;
frontmatter["type"] = "plugin";
})
}, 1000); */ // this timeout will prevent a bug when insert the template to an existing file that content only one empty line. When it happens, the note content is deleted. See: https://github.com/SilentVoid13/Templater/issues/1309#issuecomment-2079178033
%>
Actually, moving the renaming part to after tp.hooks also prevented the issue, and the content was not lost. Tp.hooks still executes after the renaming code (see the included logs).
<%*
tp.hooks.on_all_templates_executed(async () => {
console.log("inside tp.hooks");
//don’t insert the title as a tag because it can be long and contains space
//defTag.push(title)
let repo = await tp.system.prompt("What is the plugin repo URL ?");
const file = tp.file.find_tfile(tp.file.path(true));
await app.fileManager.processFrontMatter(file, (frontmatter) => {
frontmatter["tags"] = defTag;
frontmatter["repo"] = repo;
frontmatter["type"] = "plugin";
});
});
// start of template construct
console.log("after tp.hooks");
let title = tp.file.title;
// tags are type of list and are expressed as array
const defTag = ["Obsidian/Plugin"];
if (title.startsWith("Untitled")) {
title = await tp.system.prompt("What is the plugin name ?");
await tp.file.rename(title);
}
%>
Doesn't matter if you move the file, or whether the content is before the codeblock, or after.
This is the last version that works in any case using tp.hooks and your feedback.
<%*
/* Be sure to switch to edit mode first (live preview)
It is required so it can insert the template in existing file.
It must be called first and outside the tp.hooks. */
tp.user.Switch_to_edit_mode();
tp.hooks.on_all_templates_executed(async () => {
// tp.hooks will prevent a bug when insert the template to an existing file that content only one empty line. When it happens, the note content is deleted. See: https://github.com/SilentVoid13/Templater/issues/1309#issuecomment-2079178033
// start of template construct
let title = tp.file.title;
// tags are type of list and are expressed as array
const defTag = ["Obsidian/Plugin"];
if (title.startsWith("Untitled")) {
title = await tp.system.prompt("What is the plugin name ?");
await tp.file.rename(title);
}
//don’t insert the title as a tag because it can be long and contains space
//defTag.push(title)
let repo = await tp.system.prompt("What is the plugin repo URL ?");
const file = tp.file.find_tfile(tp.file.path(true));
await app.fileManager.processFrontMatter(file, (frontmatter) => {
frontmatter["tags"] = defTag;
frontmatter["repo"] = repo;
frontmatter["type"] = "plugin";
});
await tp.file.move("Categories/Tutos/Obsidian/Plugins/" + title);
});
%>
# Description
<% tp.file.cursor(1) %><%* app.workspace.activeLeaf.view.editor?.focus(); %>
# Comment je m’en sers
# Shortkeys
| Shortkeys | Actions |
| --------- | ------- |
| | |
| | |
Content of my script Switch_to_edit_mode.js:
function switch_to_editmode () {
/* Be sure to switch to edit mode first (live preview)
It is required so it can insert the template in existing file. */
const view = app.workspace.activeLeaf.getViewState()
view.state.mode = 'source'
view.state.source = false
app.workspace.activeLeaf.setViewState(view)
}
module.exports = switch_to_editmode;
Thanks.
I'm afraid the issue still exists for me as of 2.3.1. Again using
<%*
tp.hooks.on_all_templates_executed(async () => {
const file = tp.file.find_tfile(tp.file.path(true));
await app.fileManager.processFrontMatter(file, (frontmatter) => {
frontmatter["key"] = "value";
});
});
%>
TEXT THAT SHOULD STAY
on a new empty file the text that should stay doesn't stay. However, now the text doesn't pop up for half a second before it disappears which it used to do.
Should be fixed in 2.3.2!
Should be fixed in 2.3.2!
I re-tested @Fred-Vatin's previously problematic template here, and can confirm that the fix seems to have worked 🎉
<%* tp.hooks.on_all_templates_executed(async () => { const file = tp.file.find_tfile(tp.file.path(true)); await app.fileManager.processFrontMatter(file, (frontmatter) => { frontmatter["key"] = "value"; }); }); %> TEXT THAT SHOULD STAYon a new empty file the text that should stay doesn't stay. However, now the text doesn't pop up for half a second before it disappears which it used to do.
However, when testing this simple template, the text stays but the frontmatter disappears (which is strange, since @simonalveteg reported that the text would disappear):
However, I can't reproduce it reliably. Sometimes, the frontmatter stays, sometimes it disappears.
Here a time where it worked:
But I suppose the above doesn't apply directly to this issue, because the issue is about inserting templates into blank notes. In the above testing, I was creating a new note from a template.
I can't reproduce the issue when inserting the template, so I suppose the fix did work. So it's only creating new notes from templates that is bugging out, sometimes.
Reverted the fix for this template as it was causing more harm than good, will look into this further when I get a chance.
Still having this issue, any updates?
Still running into the issue as well.
Any chances of looking into this issue?
I've tried several of the examples multiple times using a variety of methods of execution (insert command, create command, folder templates) and haven't been able to reproduce.
I'm going to close this as the conversation is hard to follow what parts are working vs not working in the latest version of Templater.
Please open a new issue with a reproducible example, ideally with a video.
Here is a new ticket with simple repro. It's no different than this ticket's original post's description honestly. https://github.com/SilentVoid13/Templater/issues/1569