New note template꞉ Template inception

Published with Share Note 🔸 Part of Obsidian guides

This is my one-stop-shop for new note creation using Templater:

  1. Press the hotkey and you’re presented with a list of new note templates, based off the templates you put in a specific subfolder. These templates are just your normal Templater templates, so you can use the ones you already have:

  1. The script will ask you for the title for your new note. It will use the current date/time if no title given. Of course you can configure that as you like.

  1. And finally you can choose to insert a link to the new note into your current note:

Setup

  1. Create a template subfolder to store your templates for different types of notes, like a Project note, or a Book note, or a Person note. Add any .md template files in there that you like.
  2. Take a copy of my the Templater script at the bottom of this page and assign it to a hotkey.

Optional

If you want, you can download the entire demo vault here, which contains this script along with some other demos.

  1. Edit the script to change this value on the 4th line to the location of your template subfolder:
const templatesFolders = ['Utility/Templates/New note templates']

Template settings

Your templates can contain special properties which will configure the created new note:

template_destination_folder - This will cause the note based from this template to be created in a specific folder. For example, you might want all your Person notes to be created in a People folder.

template_title - Any text in this property will pre-fill the name for the new note field in Step 4. If you want to add a date, you can reference Moment like this: This title has the date MOMENT(YYYY-MM-DD).

Tip

These fields will be removed from the created new note, so you don’t have to worry about them cluttering up your normal notes.


The Templater script

(remove the space in < %* at the start)

< %*
// New note template configuration
 
const templatesFolders = ['Utility/Templates/New note templates']
const openNewNoteInSplit = false // Set this to true if you want the new note to open in a split to the right
 
/*
Full instructions here: https://share.note.sx/2rskmna5
*/
 
 
// -------------------------------------
// Nothing to configure after this point
// -------------------------------------
 
const templateFiles = []
for (const folder of templatesFolders) {
  const files = (await app.vault.adapter.list(folder))?.files || []
  files.sort((a, b) => a.localeCompare(b)) // Sort alphabetically
  templateFiles.push(...files)
}
if (!templateFiles) return
const templates = templateFiles.map(path => {
  const file = app.vault.getAbstractFileByPath(path)
  const meta = app.metadataCache.getFileCache(file)?.frontmatter || {}
  let title = meta.template_title || ''
  // Date/time placeholder replacement
  const match = title.match(/MOMENT\((.*?)\)/)
  if (match) title = title.replace(/(MOMENT\(.*?\))/, moment().format(match[1]))
 
  return {
    label: file.basename,
    title,
    templatePath: file.path,
    destinationFolder: meta.template_destination_folder
  }
})
 
/**
 * Create a new note from a Templater template.
 * @param {string} templatePath - Full vault path to the template file
 * @param {string} newNoteName - Title / filename of the new note
 * @param {string} destinationFolder - Full vault path to the destination folder
 * @param {boolean} [openNewNote] - Optional: Open the new note after creating it
 */
async function createFromTemplate (templatePath, newNoteName, destinationFolder, openNewNote = false) {
  destinationFolder = destinationFolder || tp.file.folder(true)
  const newFile = await tp.file.create_new(tp.file.find_tfile(templatePath), newNoteName, openNewNote, app.vault.getAbstractFileByPath(destinationFolder))
  // Remove the template properties from the new file
  app.fileManager.processFrontMatter(newFile, (frontmatter) => {
    delete frontmatter.template_destination_folder
    delete frontmatter.template_title
  })
  return openNewNote ? '' : `[[${newNoteName}]]`
}
 
/**
   * Takes a note filename/title, and replaces any filesystem-unsafe characters
   * with Unicode characters that look the same
   * @param {string} title 
   * @returns {string}
   */
function makeFilesystemSafeTitle (title) {
  // https://stackoverflow.com/questions/10386344/how-to-get-a-file-in-windows-with-a-colon-in-the-filename
  // some replacements: ” ‹ › ⁎ ∕ ⑊ \︖ ꞉ ⏐
  title = title.replace(/:/g, '꞉')
  title = title.replace(/\//g, '∕')
  return title
}
 
const chosen = await tp.system.suggester(templates.map(x => x.label), templates)
if (!chosen) return ''
let title = (await tp.system.prompt('Name for the new file. Will use the current date/time if no value given.', chosen.title || '')) || moment().format('YYYY-MM-DD HH꞉mm꞉ss')
if (typeof title !== 'string') return '' // Prompt was cancelled
title = makeFilesystemSafeTitle(title)
const addLink = await tp.system.suggester(['Yes', 'No'], [true, false], false, 'Insert link in the current file? (Escape = no)')
const destination = chosen.destinationFolder || tp.file.folder(true)
const result = await createFromTemplate(chosen.templatePath, title, destination, !addLink && !openNewNoteInSplit)
if (openNewNoteInSplit) {
  // Open the new file in a pane to the right
  const file = app.vault.getAbstractFileByPath(`${destination}/${title}.md`)
  // Create the new leaf
  const newLeaf = app.workspace.getLeaf('split')
  await newLeaf.openFile(file)
  // Set the view to edit mode
  const view = newLeaf.getViewState()
  view.state.mode = 'source'
  newLeaf.setViewState(view)
  // Give focus to the new leaf
  app.workspace.setActiveLeaf(newLeaf, { focus: true })
  // Move the cursor to the end of the new note
  app.workspace.activeLeaf.view.editor?.setCursor({ line: 999, ch: 0 })
}
return result
%>