Template
Command: template-json
Description: Apply a Liquid template to the working data. The entire working data is injected as an object or string in a variable called 'data'. Variables are injected as a variable called 'vars'.
Arguments
-
template: Liquid template string -
source: Liquid template string -
url: URL to fetch template from -
selector: CSS selector to get template from DOM
Notes
Templating is via LiquidJS. The JSON will be injected as an object named data.
Assuming a JSON object like this:
{
"name": {
"first": "Deane",
"last": "Barker"
},
"age": 54
}
We can template like this:
template-json -template:$template
$template
<strong>Name:</strong> {{ data.name.last }}, {{ data.name.first }}
<br/>
<strong>Age:</strong> {% if data.age > 50 %}Old{% else %}Not Quite Old{% endif %}
The above example passes in the template directly as an argument, but there are two other options for getting the template string.
From an external URL, via HTTP:
template-json -url:http://my.web.site/template.liquid
Or from the text content of a page element:
template-json -selector:template#person
If you're iterating the object properties "blind," note that LiquidJS will turn properties into a two-element array, with the property name as the first element, and the property value as the second element.
Assuming data is an array of objects, this is how to manually generate a simple table.
<table>
<tr>
{% for field in data.first %}
<th>{{ field[0] }}</th>
{% endfor %}
</tr>
{% for row in data %}
<tr>
{% for field in row %}
<td>{{ field[1] }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
Source Code
import { getLiquidEngine } from "../helpers.js";
async function templateJson(working, command, p) {
// Get all arguments upfront
const template = command.getArg("source,template");
const url = command.getArg("url");
const selector = command.getArg("selector");
if (template == null && url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch template from ${url}: ${response.status} ${response.statusText}`);
}
template = await response.text();
}
if (template == null && selector) {
const el = document.querySelector(selector);
if (!el) {
throw new Error(`Selector "${selector}" did not match any elements`);
}
template = el.innerHTML;
}
// TODO: I need to figure out a Node equivalent
const engine = getLiquidEngine();
if (typeof window !== "undefined" && window.liquidFilters) {
for (const [name, fn] of Object.entries(window.liquidFilters)) {
engine.registerFilter(name, fn);
}
}
let data;
try {
data = JSON.parse(working.text);
} catch (e) {
// If it's not JSON, just inject it as a string
data = working.text;
}
try{
const renderedText = await engine.parseAndRender(template, {
data: data,
vars: Object.fromEntries(working.vars),
});
return renderedText;
} catch(e) {
throw new Error(`Error rendering template: ${e.message}`);
}
}
// Meta
templateJson.title = "Template";
templateJson.description =
"Apply a Liquid template to the working data. The entire working data is injected as an object or string in a variable called 'data'. Variables are injected as a variable called 'vars'.";
templateJson.args = [
{
name: "template",
type: "string",
description: "Liquid template string",
},
{
name: "source",
type: "string",
description: "Liquid template string",
},
{
name: "url",
type: "string",
description: "URL to fetch template from",
},
{
name: "selector",
type: "string",
description: "CSS selector to get template from DOM",
},
];
templateJson.parseValidators = [
{
test: (command) => {
return (
command.hasArg("template") ||
command.hasArg("source") ||
command.hasArg("url") ||
command.hasArg("selector")
);
},
message:
"You must provide a template, a URL to fetch a template from, or a templateSelector.",
},
];
export default templateJson;