Hello. I’m having some issues with the Templater API.
My vault is a repository of mathematics notes. My goal is to create new notes based on templates (Axiom, Concept, Corollary, Definition, etc.). Every template (except for two: Subject and Reference) will have the same required properties: tags
, id
, subject
, source
. Subject requires just a tag
and id
; and Reference requires information for citation (title
, author
, publisher
, etc.). The tag
and id
of a note are automated; tag
is just the name of the template; id
is the time in YYYYMMDDHHMMSS
format, which creates a unique id
and also allows me to reference the chronology of the notes. Currently, each template has the tag
(albeit, in a slightly different format) entered into the template file properties. These are also the only tags in my vault (they are of the form #AXM
, etc., also, I’ll probably update them to #axiom
, etc. for simplicity). The property values are mostly text, with a few being lists or outright numbers (due to the Templates core plugin not playing well with the properties, the id
field is registered as text because it originally called {{date}}{{time}}
and Obsidian evaluates that as text, not a number.
I have very little experience with JavaScript so I asked for help from my friendly neighborhood artificial intelligence to get me started. Because this project is broad and I think the issues I’m having (hopefully) are just syntactical, I’m going to limit how much I add to the post here, with plans to add it to GitHub once the foundation is set. Currently “my” (I’m thinking a 60:40 split) code looks like this:
const fs = require('fs').promises;
const tp = app.plugins.plugins['templater-obsidian'];
async function formatDateToId() {
...
return id
}
async function getSubject() { // This was being returned to console if I call it within the template file
try {
const absolutePath = '/home/df/Obsidian/math/Zettelkasten/Subjects/';
const files = await fs.readdir(absolutePath);
const subjects = files.map(file => file.replace('.md', ''));
console.log(subjects);
const chosenSubject = await tp.system.suggester(subjects, subjects);
return chosenSubject;
} catch (err) {
console.error('Error reading directory:', err);
return [];
}
}
async function getSource() { // essentially the same as getSubject()
...
}
async function generateStandardFrontmatter() {
const tag = getTag(tp); // for all references
const id = formatDateToId(new Date());
const subject = getSubject();
const source = getSource();
console.log('generateStandardFrontmatter: ', tag, id, subject, source)
return `---
tags: ${tag}
id: "${id}"
subject: ${subject}
source: ${source}
---`;
}
async function generateReferenceFrontmatter() { // same as standard, except many more fields
...
}
async function getTag() {
// is getTag required? if I call the template name, can't that be the tag? instead of #AXM I can just use #axiom, etc.
// getTag informs frontmatter generator functions of the template to pull.
// this is because there is only one tag on a newly created file.
console.log('getTag starting')
const tag = tp.file.tags();
console.log('getTag: ', tag);
return tag;
}
async function main() {
console.log('getTag next');
const tag = await getTag(); \\ this is where I get an error
console.log('main: ', tag);
console.log('formatDateToId next');
const id = await formatDateToId(); \\ this is fine
console.log('main: ', id);
console.log('letting frontmatter')
main()
module.exports = { formatDateToId, ...}
Still here? Thanks.
For simplicity, let’s focus on getTag()
, which is where I’m currently having an issue. Templater does not trigger automatically on file creation. What I have is this:
---
tags:
- AXM
id:
subject:
source:
---
### Axiom
<% tp.user.main.main() %>
which when called with “Alt + Shift + Q
=> Templater: Create new note from template,” returns this in the console:
getTag next
getTag starting
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'tags')
at getTag (eval at load_user_script_function (plugin:templater-obsidian:1:1),
<anonymous>:188:25)
at main (eval at load_user_script_function (plugin:templater-obsidian:1:1),
<anonymous>:195:23)
at anonymous (eval at load_user_script_function (plugin:templater-obsidian:1:1),
<anonymous>:221:1)
at UserScriptFunctions.load_user_script_function (plugin:templater-obsidian:2949:7)
at async UserScriptFunctions.generate_user_script_functions (plugin:templater-obsidian:2933:9)
at async UserScriptFunctions.generate_object (plugin:templater-obsidian:2963:35)
at async UserFunctions.generate_object (plugin:templater-obsidian:2982:31)
at async FunctionsGenerator.generate_object (plugin:templater-obsidian:3023:33)
at async Templater.parse_template (plugin:templater-obsidian:3505:30)
at async errorWrapper (plugin:templater-obsidian:78:12)
So, my question is this: why is it that when I create
const tp = app.plugins.plugins['templater-obsidian'];
does the app not recognize tp.file.tags();
but it does recognize file
?