Create Javascript objects from a template
Solution 1
So I've managed to solve this by (ab)using functions as metadata to mark the values that should be replaced in the template. This is made possible by two things:
- I only need valid JSON values, so I can safely say that functions aren't literal user input
- JSON.stringify has a replacer parameter which will traverse the object and can be used to pass the input data to the template
Using a template generator like this
var templateMaker = function (object) {
return function (context) {
var replacer = function (key, val) {
if (typeof val === 'function') {
return context[val()]
}
return val;
}
return JSON.parse(JSON.stringify(obj, replacer))
}
}
I create a template object, replacing field names with functions that return the field name
var obj = {
name: "Alfred",
stats: {
age: 32,
position: {
title: function () { return 'title' },
level: function () { return 'level' }
}
}
}
then I create the template function, define my input, and render it to an object
var template = templateMaker(obj);
var data = {
title: "Manager",
level: 10
}
var rendered = template(data);
and magically, the object output looks like
{
"name": "Alfred",
"stats": {
"age": 32,
"position": {
"title": "Manager",
"level": 10
}
}
}
Solution 2
Maybe template engines like Mustache would help you with this.
You can define your object template in string:
var template = '{ title: {{title}} }';
then render it with the data, and convert it to json:
var data = {title: 'I am title'};
var obj = JSON.parse(Mustache.render(template, data));
UPDATE:
I read your updated example, here is the corresponding example:
var template = JSON.stringify({
name: "Alfred",
stats: {
age: 32,
position: {
level: 10,
title: '{{title}}'
}
}
});
var data = {title: 'I am title'};
var obj = JSON.parse(Mustache.render(template, data));
obj.stats.position.title == "I am title";
Drew Greene
Updated on July 21, 2022Comments
-
Drew Greene almost 2 years
I want to create a javascript object from a template. The problem is I don't know what the template is going to look like beforehand. As a simple example, if I had the template function
template = function (data) { return { title: data.title } }
then I could run
template({ title: "Steve" })
and get back the object{ title: "Steve" }
Because
data.title
is not evaluated until I call the template function. But I'm constructing an object based on user input where the field names are not known beforehand and could be deeply nested anywhere in the object.If I define the object that is returned beforehand then the
data.title
field in the example would already be evaluated and wouldn't use the input data. For example, I want to be able to define the template object likeobj = { title: this.title }
then redefine the template as
template = function () { return obj }
and call
template.call({title:"Steve"})
. But currently I get back{ title: undefined }
because
this.title
was already evaluated when I definedobj
. Maybe I'm approaching this the wrong way, because I keep coming to the conclusion that I'd have to modify the function by stringifying it, modifying the string to include the unevaluated codethis.title
and creating a new function from the string. But that seems like a plain awful idea.And traversing the object looking for special values to replace seems expensive and complicated. I also looked for some sort of javascript object templating library but didn't find anything.
EDIT: To make it more clear that the input data and the template structure won't necessarily match, I may want have a template that looks like
template = function (data) { return { name: "Alfred", stats: { age: 32, position: { level: 10, title: data.title } } } }
and call
template({title:"Manager"})
to get{ "name": "Alfred", "stats": { "age": 32, "position": { "level": 10, "title": "Manager" } } }
-
Drew Greene about 10 yearsThanks. I did consider something like this but since the user will dictate the other values in the object, I wasn't sure how to distinguish my template
{{var}}
from user input where they literally wanted the string "{{var}}". Is there perhaps a trivial way to do this I'm missing? -
Rahul Singh about 6 years@wong2 it always gives unexpected token t at position how to fix this