Templater - Use Filename from Suggester for rename

Things I have tried

searching though github and documentation of templater, google and the forum … but didnt find the right searchterm i guess
wasted an afternoon with trial and error and now i dont know how to proceed other than ask for help here

What I’m trying to do

I have a template where I use a tp.system.suggester(suggestions,values) to get a link to a note to be used inside my template - that works great.

Now I would love to use that notes fileName in the filename of the newly created note. But I dont know how to access the “suggestion” part of the selected value i get out of the suggester.

suggestion would be like “LastName, Firstname”
value would be like “[[people/contactlist/project/Lastname, Firstname.md|Lastname, Firstname]]”

so in short: i have a variable with a file-link and just want the file-name (without the path and extension).

i am sure this is a simple syntax thing that i just dont find
thank you guys

1 Like

Please provide your current code, so we can see what you’ve tried, and so that we have something to test with.

 const dv = this.app.plugins.plugins["dataview"].api; 
 let people = dv.pages("#person").file.sort(n => n.name); 
 let suggestions = people.name;
 let values = people.link; 

let person = await tp.system.suggester(suggestions,values);
const title = tp.file.creation_date("YYYY-MM-DD") + " - "  + person;

await tp.file.rename(title) 

I tried person.name, person.basename, person.file.name … looking at the console (if i log the person variable) its a complex array - but no filename - only the path is there.

so i tried a regex - but wasn’t successful …

i do have a workaround for now:
using

let person = await tp.system.suggester(suggestions,suggestions);

and adding [[]] around the person in the template:

Contact:: [[<%* tR += person %>]]

but this is semi cool if there is two files with the same name somewhere in my vault.
so a direct way to get the file.name for use in the rename and the filepath-link for the “contact” would be preferred

So to get the filename without the .md extension, and build the new title, you can do the following:

const onlyFilename = person.path.split('/').pop().slice(0, -3)
const title = tp.file.creation_date("YYYY-MM-DD") + " - "  + onlyFilename;

All that dotted fun, chains together to do:

  • Get the path out of the person object, as you most likely saw in the console
  • split('/') – Splits the path into it’s separate components, and returns an array with each of them
  • pop()– Get the last item of an array, in our case the filename with the .md part
  • slice(0, -3) – Get just a slice of the string, starting at the begin, and skip the last three characters. In effect, loose the .md part

Another option if you want both the filename (without the extension), and the folder in which the file resides, you can try the following:

const [folder, filename] = person.path
                                 .match(/^(.*)\/([^\/]+)\.md$/)
                                 .slice(1)

The explanation of this is a little hairier, but it goes as follows:

  • Use the person.path as the starting point, as before
  • Do a regex match(/ ... /) on it to pick out two parts:
    • ^ – Lock at the start of string
    • (.*)\/ – Capture, ( ... ), any string, .*, up until it matches a literal forward slash, \/. Be as greedy as possible and get as much as possible
    • ([^\/]+) – Do another capture group, ( ... ), but this time match characters not being the forward slash, [^\/], and get at least one character, +.
    • \.md$ – Finally match against the actual period character, \., followed by the string md, until the end of the string $
  • The match(...) will now return three groups, firstly the entire matched string, and then the first and second group. We only care for the last two, so we do a slice(1) to get everything from the element at index 1 (which since 0 is the first, actually is the second :-D)
  • Finally store these two array values into the variables folder and `filename``

Due to the natural greediness of the first capture group in the match(), and the restriction to not include any slashes in the second, the first group will gobble up all folders and subfolders, and leave a clean filename for the second capture group.

Hope this helps you on your way forward!

1 Like

A caveat with the previous regex is if the person file is in the root folder. To accommodate for that you need to change the match() into this:

.match(/^(?:(.*)\/)?([^\/]+)\.md$/)

There is an addition of a non-capturing group, (?: ... ), which surrounds the first part including the obligatory forward slash, but due to the addition of the ? (after the part \/)) this first group can exists zero or one time. In other words, it can be missing.

If it’s missing, like with persons residing in the root folder, the folder variable will be left undefined. So take care if that is a case you might run into, you might want it to be set to "" or similar, if it’s undefined. Like in:

folder = folder == undefined ? "" : folder
1 Like

wow!! simply wow. thanks for the time and effort to explain the regex to me. i will try this as soon as im back in the office. thank you!

1 Like