How to make a button to create a new note using meta-bind-js-view using YAML properties

The goal of thi sexercise was to create a meta-bind button to create a new note that retrieved the template and folder path declaration from the current note’s frontmatter YAML properties:

TMP_PATH, template file declaration use
LOG_PATH, folder path declaration use

Enter each path as a vault root relative path with no quotes

The following meta-bind-js-view code block is used to create the button:

{TMP_PATH} as templatePath
{LOG_PATH} as logPath
---
const buttonString = `
~~~meta-bind-button
label: "📝 Create New Project Log"
icon: ""
hidden: false
class: "button-43"
tooltip: "Create a new note from template"
id: ""
style: primary
actions:
  - type: templaterCreateNote
    templateFile: ${context.bound.templatePath}
    folderPath: ${context.bound.logPath}
    openNote: true
~~~
`;

return engine.markdown.create(buttonString);

Hope Folks Find This Useful
Best Regards
-Tim C.

Next step will be to retrieve the YAML from a different note located in a central location, Eg at the vault Root

The button described above is / will be part of a project directory structure. It is essentially a starting framework for a new project. When new project is required a copy of the directory structure is created. A few YAML frontmatter paths will be edited in a master “PROJ_INFO” file. And then the subdirectory automation objects will retrieve those paths to get that project up and running.

Here is the code setup for the button to retrieve the path for the template file and folder path where the new note will be stored when the button is used to create a new note:

This button is placed in a note that runs a dataview query to retrieve a list of all the Project Logs currently stored in the project sub directory:

BUTTON CODE THAT RETRIEVES PATH INFO FROM FILE IN THE SAME DIRECTORY:

{fileName} as currentFileName
---
const path = require('path');
const fs = require('fs');

// Get the vault's base path
const vaultPath = app.vault.adapter.basePath;

// Construct the path to the PROJ_INFO file (located in the same directory as the current note)
const projInfoPath = path.join(vaultPath, path.dirname(app.workspace.activeLeaf.view.file.path), 'PROJ_INFO.md');

// Log the path to verify it's correct
console.log("projInfoPath:", projInfoPath);

// Read the content of the PROJ_INFO file
let projInfoContent;
try {
  projInfoContent = fs.readFileSync(projInfoPath, 'utf-8');
} catch (err) {
  console.error("Error reading PROJ_INFO file:", err);
  return "❌ Error: Failed to read PROJ_INFO.md";
}

// Extract the frontmatter for PATH_PRJLOGS and PATH_PRJLOG_TMP
const frontmatter = projInfoContent.match(/---([\s\S]*?)---/);
let templatePath = '';
let logPath = '';

if (frontmatter) {
  const frontmatterContent = frontmatter[1];

  // Regex to extract the values for PATH_PRJLOGS and PATH_PRJLOG_TMP
  const logPathMatch = frontmatterContent.match(/PATH_PRJLOGS:\s*(.*)/);
  const templatePathMatch = frontmatterContent.match(/PATH_PRJLOG_TMP:\s*(.*)/);

  if (logPathMatch) {
    logPath = logPathMatch[1].trim();
    console.log("logPath:", logPath);
  }
  if (templatePathMatch) {
    templatePath = templatePathMatch[1].trim();
    console.log("templatePath:", templatePath);
  }
}

if (!templatePath || !logPath) {
  return "❌ Error: Missing template or log path in PROJ_INFO.md";
}

const buttonString = `
~~~meta-bind-button
label: "📝 Create New Project Log"
icon: ""
hidden: false
class: "button-43"
tooltip: "Create a new project log entry from template"
id: ""
style: primary
actions:
  - type: templaterCreateNote
    templateFile: ${templatePath}
    folderPath: ${logPath}
    openNote: true
~~~
`;

// Log the button string to verify its creation
console.log("buttonString:", buttonString);

return engine.markdown.create(buttonString);

Best Regards
-Tim C.

HERE IS THE SOURCE CODE FOR THE INDEX FILE THAT RUNS THE DATAVIEW QUERY TO RETRIEVE THE PROJECT LOGS FROM THE PROJECT SUB-DIRECTORY:


PROJ_ID:
PROJ_NAME:
NTYPE: PROJECT LOG INDEX
TMP_PATH: 04 - ACTIVE PROJECTS/_PROJECT TEMPLATE/07 PROJECT LOGS/TMP - PROJECT LOG.md
LOG_PATH: 04 - ACTIVE PROJECTS/_PROJECT TEMPLATE/07 PROJECT LOGS
SORT_ORDER: ASCENDING
NAME_FORMAT: DATE

HARD CODED

label: "CREATE A NEW MEETING LOG"
icon: ""
hidden: false
class: ""
tooltip: ""
id: ""
style: default
actions:
  - type: templaterCreateNote
    templateFile: 04 - ACTIVE PROJECTS/_PROJECT TEMPLATE/07  PROJECT LOGS/TMP - PROJECT LOG.md
    folderPath: 04 - ACTIVE PROJECTS/_PROJECT TEMPLATE/07  PROJECT LOGS
    openNote: true

META BIND YAML CODED

{TMP_PATH} as templatePath
{LOG_PATH} as logPath
---
const buttonString = `
~~~meta-bind-button
label: "📝 Create New Project Log"
icon: ""
hidden: false
class: "button-43"
tooltip: "Create a new project log entry from template"
id: ""
style: primary
actions:
  - type: templaterCreateNote
    templateFile: ${context.bound.templatePath}
    folderPath: ${context.bound.logPath}
    openNote: true
~~~
`;

return engine.markdown.create(buttonString);

META BIND RETRIEVING YAML FROM PROJ_INFO

{fileName} as currentFileName
---
const path = require('path');
const fs = require('fs');

// Get the vault's base path
const vaultPath = app.vault.adapter.basePath;

// Construct the path to the PROJ_INFO file (located in the same directory as the current note)
const projInfoPath = path.join(vaultPath, path.dirname(app.workspace.activeLeaf.view.file.path), 'PROJ_INFO.md');

// Log the path to verify it's correct
console.log("projInfoPath:", projInfoPath);

// Read the content of the PROJ_INFO file
let projInfoContent;
try {
  projInfoContent = fs.readFileSync(projInfoPath, 'utf-8');
} catch (err) {
  console.error("Error reading PROJ_INFO file:", err);
  return "❌ Error: Failed to read PROJ_INFO.md";
}

// Extract the frontmatter for PATH_PRJLOGS and PATH_PRJLOG_TMP
const frontmatter = projInfoContent.match(/---([\s\S]*?)---/);
let templatePath = '';
let logPath = '';

if (frontmatter) {
  const frontmatterContent = frontmatter[1];

  // Regex to extract the values for PATH_PRJLOGS and PATH_PRJLOG_TMP
  const logPathMatch = frontmatterContent.match(/PATH_PRJLOGS:\s*(.*)/);
  const templatePathMatch = frontmatterContent.match(/PATH_PRJLOG_TMP:\s*(.*)/);

  if (logPathMatch) {
    logPath = logPathMatch[1].trim();
    console.log("logPath:", logPath);
  }
  if (templatePathMatch) {
    templatePath = templatePathMatch[1].trim();
    console.log("templatePath:", templatePath);
  }
}

if (!templatePath || !logPath) {
  return "❌ Error: Missing template or log path in PROJ_INFO.md";
}

const buttonString = `
~~~meta-bind-button
label: "📝 Create New Project Log"
icon: ""
hidden: false
class: "button-43"
tooltip: "Create a new project log entry from template"
id: ""
style: primary
actions:
  - type: templaterCreateNote
    templateFile: ${templatePath}
    folderPath: ${logPath}
    openNote: true
~~~
`;

// Log the button string to verify its creation
console.log("buttonString:", buttonString);

return engine.markdown.create(buttonString);

SORT ORDER

INPUT[select(option(ASCENDING), option(DESCENDING)):SORT_ORDER]

NAME FORMAT

INPUT[select(option(FULL), option(SHORT), option(DATE)):NAME_FORMAT]

Project Log Index

let currentFolder = app.workspace.getActiveFile().parent.path; // Get the current folder path
let currentNote = app.workspace.getActiveFile().path; // Get the current note's full path
let currentNoteData = dv.page(currentNote); // Load the current note's YAML data

if (!currentNoteData) {
    dv.header(2, "Current note's YAML data not found");
} else {
    // Retrieve the DATA_PRJLOGS path from the PROJ_INFO note in the current folder
    let projectInfoPath = currentFolder + "/PROJ_INFO.md"; // Construct the path to the Project Info note
    let projectInfo = dv.page(projectInfoPath); // Load the Project Info note

    if (!projectInfo) {
        dv.header(2, "Project Info not found in the current folder");
    } else {
        let projectLogsPath = projectInfo.DATA_PRJLOGS; // Retrieve the DATA_PRJLOGS field from PROJ_INFO YAML

        // Retrieve the SORT_ORDER value from the current note's YAML (default to ASCENDING)
        let sortOrder = currentNoteData.SORT_ORDER || "ASCENDING"; // Default to ASCENDING if undefined
        let sortDirection = sortOrder.toUpperCase() === "DESCENDING" ? "desc" : "asc"; // Map SORT_ORDER to sorting direction

        // Retrieve the NAME_FORMAT value to determine string parsing use case
        let nameFormat = currentNoteData.NAME_FORMAT || "FULL"; // Default to FULL if undefined

        // Query project logs from the specified folder and filter out files containing "TMP"
        let projectLogs = dv.pages(`"${projectLogsPath}"`) // Query from the specified path
            .where(p => !p.file.name.toUpperCase().includes("TMP")) // Exclude files with "TMP" in the name
            .sort(p => p.file.name.slice(-10), sortDirection); // Sort by the rightmost 10 characters in the file name

        // Create a table with results
        dv.table(
            ["LINK", "SUMMARY"], // Column headers
            projectLogs.map(p => {
                // Determine the displayed name based on the NAME_FORMAT value
                let displayName;

                if (nameFormat === "SHORT") {
                    // SHORT: Remove 15 characters from the middle of the file name, keeping the rest
                    let rightIndex = p.file.name.length - 11; // Calculate position for RIGHT(11)
                    displayName = p.file.name.substring(0, rightIndex - 15) + p.file.name.substring(rightIndex);
                } else if (nameFormat === "DATE") {
                    // DATE: Display only the rightmost 10 characters of the file name
                    displayName = p.file.name.slice(-10);
                } else if (nameFormat === "FULL") {
                    // FULL: Display the full file name without any parsing
                    displayName = p.file.name;
                } else {
                    // Fallback to FULL if the NAME_FORMAT value is invalid
                    displayName = p.file.name;
                }

                return [
                    dv.fileLink(p.file.name, false, displayName), // Create clickable link with the parsed name
                    p.SUMMARY || "--" // Leave blank if SUMMARY is not available
                ];
            })
        );
    }
}

One more point to make for folks new to meta-bind, you will need meta-bind and js-engine community plugins to make the button code work

1 Like