Reputation: 25
I'm making an HTML Templating Engine.
The program goes through the HTML, and finds all instances of {{ }}. It then goes through all the keys in our countroller, and replaces instances of variable names with a reference to the controller.
For example, if my controller is {name:"grody"}
and my HTML has {{name}}
, my program will do the following would replace that with {{ctrl['name']}}
.
Then the program goes through and will use eval()
on all the expressions to evaluate them.
So something like {{name + " joe"}}
--> {{ctrl['name'] + " joe"}}
--> grody joe
The error I'm getting is a ReferenceError, obviously happening within the eval
of the function. This ReferenceError is only occurring when there is more than one variable, and it will throw an error on the first variable.
For example, if the template is {{name}} is {{age}} years old}}
it will get a ReferenceError on name.
However, if you make the name a string, so something like "na+me":"grody"
in the controller will cause a ReferenceError: na is not defined.
This is the code:
function template(str, ctrl) {
var exp = str.match(/[^{{]+(?=\}})/g).map(function(x) {
return x.replace("}}", "")
})
for (var i = 0; i < exp.length; i++) {
for (var prop in ctrl) {
//console.log("propSearch:", prop.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'))
var evalExp = exp[i].replace(new RegExp(prop.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), "g"), "ctrl['" + prop + "']")
str = str.replace(new RegExp("{{" + exp[i].replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + "}}", "g"), eval(evalExp))
//console.log(prop)
//console.log("exp[i]:", exp[i])
//console.log("evalExp:", evalExp)
//console.log("search:", exp[i].replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'))
//console.log("eval:", eval(evalExp))
//console.log("str", str)
evalExp = ""
}
}
return str
}
Upvotes: 0
Views: 42
Reputation: 4106
I think you're making this a lot more complicated than it needs to be. I don't really understand why all those regular expressions and replaces are necessary. Here's a function that accomplishes what you're looking for:
const mustache = /\{\{(\w+)\}\}/g;
function template(str, ctrl) {
return str.replace(mustache, (match, key) => ctrl[key]);
};
It's pretty rudimentary (it can only handle primitive string keys, but not expressions), but you can work on the callback passed to .replace()
to make it smarter.
Upvotes: 1