Templater icon indicating copy to clipboard operation
Templater copied to clipboard

tp.file.move() doesn't create new directory

Open htmljenn opened this issue 2 years ago • 15 comments

Plugin information (please complete the following information):

  • OS: iPadOS 15.5
  • Templater version: 1.12.0
  • Obsidian version: Mobile 1.2.2 (56)
  • Templater settings: folder location: [00 Meta/04 templates], Timeout: unknown, could not find in settings.

Describe the bug I have a journal note that places daily entries into a folder by month and year. I use this template daily. It uses a templater javascript block to name the file and move it to the correct location. Creating a new directory if it doesn't exist. Instead, it just stopped running. There did not seem to be any error message or warning that this had failed.

The templater javascript block looks like this:

<%*
let titleName = tp.date.now("YYYY-MM-DD") ;
let fileName = "💌 " + titleName
await tp.file.rename(fileName);
await tp.file.move("10 Dated Notes/11 Journal/" + tp.date.now("YYYY/YYYY-MM/") + fileName);
-%>

Expected behavior I expect the file to be created, renamed, and moved to the directory. If the directory does not exist, it should be created. It has worked every day until today - the first day of the month. I had to manually create the folder to get the template to complete.

If the template needs the directory to be created first, then an error message should appear on the screen, and remain visible until it's resolved.

Screenshots

Additional context I believe that this works on my desktop (MacOS) version of Obsidian, as I've been using this same template for several months without an issue.

htmljenn avatar Jul 01 '22 19:07 htmljenn

You can get around this by using some JS to check if folder exists and create it if it doesn't.

AB1908 avatar Jul 01 '22 21:07 AB1908

like what @AB1908 said, we need to write js to check if folder exists. See #270 #333. The code below worked for me (tested on windows and android. Idk about mac os).

<%*
	let titleName = tp.date.now("YYYY-MM-DD") ;
	let fileName = "💌 " + titleName;
	const dir = "10 Dated Notes/11 Journal/" + tp.date.now("YYYY/YYYY-MM")
	const fileDir = dir + "/" + fileName
	if (!await this.app.vault.getAbstractFileByPath(dir)) {
		// if path doesnt exist, create folders
		await this.app.vault.createFolder(dir)
		await tp.file.move(fileDir)
	} else if (await this.app.vault.getAbstractFileByPath(fileDir + ".md")) {
		// if .md file already exists, append time to avoid duplicate error
		await tp.file.move(fileDir + " " +  tp.date.now("h-mm-ss a"))
	} else {
		// if .md file doesnt exist
		await tp.file.move(fileDir)
	}
%>

Demo demo

No mobile demo sry. My mobile doesnt show nested folders that well, and I dont use mobile at all lol

Hope that helps

~welp

welpdx avatar Jul 07 '22 20:07 welpdx

@welpdx it seems very useful. Can you help please to replicate this with templaterJS script? It's painful to insert in every template.

cogscides avatar Jul 09 '22 19:07 cogscides

@cogscides, What do you mean by "templaterJS script"?

welpdx avatar Jul 09 '22 19:07 welpdx

Thanks @welpdx that worked PERFECTLY.

htmljenn avatar Jul 10 '22 00:07 htmljenn

@htmljenn yay!

welpdx avatar Jul 10 '22 04:07 welpdx

@welpdx , what if instead of making a new file with time appended at the end, you could open the already existing note and continue where you left off?

asrevni avatar Jul 28 '22 08:07 asrevni

Sure, do that with tp.file.find_tfile() and then app.vault.append().

AB1908 avatar Jul 28 '22 09:07 AB1908

@hypnosu Try this: It will check if file already exists in folder. If it does exist, it will open it up for editing.

<%*
let titleName = tp.date.now("YYYY-MM-DD");
let fileName = "💌 " + titleName;
const dir = "10 Dated Notes/11 Journal/" + tp.date.now("YYYY/YYYY-MM")
const fileDir = dir + "/" + fileName
if (!await this.app.vault.getAbstractFileByPath(dir)) {
    // if path doesnt exist, create folders
    await this.app.vault.createFolder(dir)
    await tp.file.move(fileDir)
} else if (await this.app.vault.getAbstractFileByPath(fileDir + ".md")) {
    // if .md file already exists, open file in current active leaf
    var file = await this.app.vault.getAbstractFileByPath(fileDir + ".md")
    const active_leaf = this.app.workspace.activeLeaf;
    if (!active_leaf) {
        new Notice("No active leaf", 5000);
    } else {await active_leaf.openFile(file, {state: {mode: "source"},});}
} else {
    // if .md file doesnt exist
    await tp.file.move(fileDir)
}
%>
Demo demo

welpdx avatar Jul 28 '22 17:07 welpdx

Yeah, it works, thanks! Is there any function that I could call so that the cursor automatically moves at the end of file upon opening?

asrevni avatar Jul 28 '22 21:07 asrevni

Can app.vault.append() a tp.cursor command I think but I think it could also be done via some workspace/Editor methods. Not knowledgeable enough to know what that would look like though.

AB1908 avatar Jul 28 '22 21:07 AB1908

I tried with app.vault.append() but I kept on getting this error

Cannot create property 'saving' on string

I will look into workspace methods. Thanks.

asrevni avatar Jul 28 '22 21:07 asrevni

Added two functions to script:

  1. Added @AB1908's suggestion to append currently viewed file's content to existing file (if file already exists)
  2. When opening already existing file, the cursor is placed at the end.
<%*
let titleName = tp.date.now("YYYY-MM-DD");
let fileName = "💌 " + titleName;
const dir = "10 Dated Notes/11 Journal/" + tp.date.now("YYYY/YYYY-MM")
const fileDir = dir + "/" + fileName
if (!await this.app.vault.getAbstractFileByPath(dir)) {
    // if path doesnt exist, create folders, move and rename current file to new folder
    await this.app.vault.createFolder(dir)
    await tp.file.move(fileDir)
} else if (await this.app.vault.getAbstractFileByPath(fileDir + ".md")) {
    // if .md file already exists
    // append content from current file to existing file
    var currentFile = this.app.workspace.getActiveFile()
    var file = await this.app.vault.getAbstractFileByPath(fileDir + ".md")
    await this.app.vault.append(file,"\n" + await this.app.vault.read(currentFile) + "\n")
    // open this existing file in pane
    const active_leaf = this.app.workspace.activeLeaf;
    if (!active_leaf) {
        new Notice("No active leaf", 5000);
    } else {
	    await active_leaf.openFile(file, {state: {mode: "source"},});
	    //after opening file, move cursor to the end
		const active_view=this.app.workspace.getActiveViewOfType(tp.obsidian.MarkdownView);
		if (active_view === null) {
		new Notice("error",5000)
		} else {
		const editor = active_view.editor;
		var lastlinenum = editor.lastLine();
		editor.setCursor(lastlinenum);
		}
    }
} else {
    // if fodler exists, but .md file doesnt exist, just move and rename file to target directly
    await tp.file.move(fileDir)
}
%>
Demo demo
Edit: typo, clarification, edited comments to make it clear

welpdx avatar Jul 28 '22 22:07 welpdx

Beautiful! Thank you so much! Templater 101.

asrevni avatar Jul 28 '22 23:07 asrevni

Hey no problem! Yea I learned alot from making these js scripts for different use cases lol

And thanks @AB1908 for basically the pseudo code lol

welpdx avatar Jul 29 '22 04:07 welpdx