Render an Object as a String in Final Template but Pass the Full Object to Tags #756
Replies: 4 comments
-
|
A drop with a import { Liquid, Tag, Drop, evalToken, Tokenizer } from "liquidjs";
class MyDrop extends Drop {
constructor(obj) {
super();
this.value = obj.Value;
this.type = obj.Type;
this.name = undefined;
}
lookupName() {
if (this.name === undefined) {
// TODO: database lookup here
let data = { firstName: "foo", lastName: "bar" };
this.name = `${data.firstName} ${data.lastName}`;
}
return this.name;
}
valueOf() {
return this.lookupName();
}
}
class MyTag extends Tag {
constructor(token, remainTokens, liquid) {
super(token, remainTokens, liquid);
const tokenizer = new Tokenizer(token.args);
// In this example, arguments could be a mix of literals and variables.
this.arguments = [];
while (!tokenizer.end()) {
this.arguments.push(tokenizer.readValue());
}
}
*render(ctx, emitter) {
for (const arg of this.arguments) {
let obj = yield evalToken(arg, ctx);
if (obj instanceof MyDrop) {
// Access to drop properties here.
// Outputting as a JSON string for demonstration purposes.
emitter.write(JSON.stringify({ value: obj.value, type: obj.type }));
}
}
}
}
const liquid = new Liquid();
liquid.registerTag("mytag", MyTag);
const exampleTemplate = `\
Hello, {{ someDrop }}!
{% mytag someDrop %}`;
const someObject = {
Value: "12345",
Type: "user",
};
// Wrap plain object in a drop
const someDrop = new MyDrop(someObject);
liquid.parseAndRender(exampleTemplate, { someDrop }).then(console.log);Output And captured values are always rendered strings.. // continued from above
const captureExampleTemplate = `\
{% capture foo %}
Hello, {{ someDrop }}!
{% mytag someDrop %}
{% endcapture %}
{{foo}}`;
liquid.parseAndRender(captureExampleTemplate, { someDrop }).then(console.log);Output |
Beta Was this translation helpful? Give feedback.
-
|
I confused valueOf and toLiquid when testing this in my code before posting the issue. Now it works as expected. {% assign my_variable = some_function param1 param2 %}Instead I'm thinking about doing something like: {% some_function param1 param2 set:my_variable %}And internally either set the variable or return the value depending on wether "set" is there or not. Is there a better way of doing this? (Can I even do that?) |
Beta Was this translation helpful? Give feedback.
-
That seems quite reasonable to me. The standard class MyTag extends Tag {
constructor(token, remainTokens, liquid) {
super(token, remainTokens, liquid);
const tokenizer = new Tokenizer(token.args);
// NOTE: param1 and param2 could be undefined here
this.param1 = tokenizer.readValue();
tokenizer.skipBlank();
this.param2 = tokenizer.readValue();
tokenizer.skipBlank();
const optionName = tokenizer.readNonEmptyIdentifier()?.content;
tokenizer.assert(
optionName === undefined || optionName === "set",
`expected option 'set', found '${optionName}'`
);
if (optionName !== undefined) {
tokenizer.skipBlank();
tokenizer.assert(tokenizer.peek() === ":");
++tokenizer.p; // Move past colon
tokenizer.skipBlank();
this.option = tokenizer.readNonEmptyIdentifier();
tokenizer.assert(
this.option !== undefined,
"expected option 'set' to be passed an identifier"
);
} else {
this.option = undefined;
}
}
*render(ctx, emitter) {
const obj1 = yield evalToken(this.param1, ctx);
const obj2 = yield evalToken(this.param2, ctx);
// TODO: something with obj1 and obj2
if (this.option !== undefined) {
const variableName = yield evalToken(this.option, ctx);
ctx.environments[variableName] = "some value";
}
}
} |
Beta Was this translation helpful? Give feedback.
-
|
That is perfect! Thank you both for the help, this also lets me see how things are done in a more standard way. I will close the issue now |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I’m currently using LiquidJS and I’m trying to implement the following behavior:
Example Scenario:
Let’s say I have an object structured like this:
{ "Value": "12345", "Type": "user" }{{ object }}), I want it to trigger a lookup in the database (in this case, using the Value field to find the firstName and lastName of the user) and return a string with the user's name.Specific Questions:
Is it possible to achieve this behaviour using Drops and toLiquid() and/or valueOf() in LiquidJS?
{{ object.name }}it worked. But I want to have this behaviour without having to add ".name" and simply have{{ object }}.{% capture %}tag? If I use the{% capture %}tag to store this object in a variable, will the captured variable hold the entire object (with its Value and Type fields), or will it contain the rendered string (the user's name after the database lookup)?{% capture userVar %} {{ object }} {% endcapture %}Would userVar hold the object or the rendered string (e.g., "John Doe")?
Beta Was this translation helpful? Give feedback.
All reactions