javascript 忽略下划线模板中未定义的数据/变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15283741/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ignoring undefined data / vars in an underscore template
提问by Shaz Amjad
Still learning backbone so bear with me;
还在学习骨干,请耐心等待;
I'm trying to add a new model with blank fields to a view, but the template I've created has a whole bunch of
我正在尝试向视图添加一个带有空白字段的新模型,但是我创建的模板有一大堆
<input value="<%= some_value %>" type="whatever" />
Works perfectly fine when fetching data, it populates it and all goes well. The trouble arises when I want to create a new (blank) rendered view, it gives me
获取数据时工作得很好,它填充数据并且一切顺利。当我想创建一个新的(空白)渲染视图时,问题就出现了,它给了我
Uncaught ReferenceError: some_value is not defined
I can set defaults
(I do already for a few that have default values in the db) but that means typing out over 40 of them with blanks; is there a better way of handling this?
我可以设置defaults
(我已经设置了一些在数据库中有默认值的设置)但这意味着用空格输入 40 多个;有没有更好的方法来处理这个问题?
I'm fiddling around with the underscore template itself, trying something like <%= if(some_value != undefined){ some_value } %>
but that also seems a bit cumbersome.
我正在摆弄下划线模板本身,尝试类似的东西,<%= if(some_value != undefined){ some_value } %>
但这似乎也有点麻烦。
采纳答案by Benjamin Gruenbaum
No,
不,
There is no actual fixfor this due to the way underscore templates are implemented.
由于下划线模板的实现方式,没有实际解决此问题的方法。
See this discussionabout it:
请参阅有关它的讨论:
I'm afraid that this is simply the way that with(){} works in JS. If the variable isn't declared, it's a ReferenceError. There's nothing we can do about it, while preserving the rest of template behavior.
恐怕这只是 with(){} 在 JS 中的工作方式。如果未声明变量,则为 ReferenceError。我们对此无能为力,同时保留模板行为的其余部分。
The only way you can accomplish what you're looking for is to either wrap the object with another object like the other answer suggested, or setting up defaults.
您可以完成您正在寻找的唯一方法是用另一个对象包装对象,如建议的其他答案,或者设置默认值。
回答by jevakallio
Pass the template data inside a wrapper object. Missing property access won't throw an error:
在包装器对象中传递模板数据。缺少属性访问不会引发错误:
So, instead of:
所以,而不是:
var template = _.template('<%= foo %><%= bar %>');
var model = {foo:'foo'};
var result = template(model); //-> Error
Try:
尝试:
var template = _.template('<%= model.foo %><%= model.bar %>');
var model = {foo:'foo'};
var result = template({model:model}); //-> "foo"
回答by Dmitriy
Actually, you can use arguments
inside of your template:
实际上,您可以arguments
在模板内部使用:
<% if(!_.isUndefined(arguments[0].foo)) { %>
...
<% } %>
回答by kirschpirogge
If you check source code for generated template function, you will see something like this:
如果您检查生成的模板函数的源代码,您将看到如下内容:
with (obj||{}) {
...
// model property is used as variable name
...
}
What happens here: at first JS tries to find your property in "obj", which is model (more about withstatement). This property is not found in "obj" scope, so JS traverses up and up until global scope and finally throws exception.
这里发生了什么:首先 JS 尝试在“obj”中找到您的属性,这是模型(更多关于with语句)。这个属性在“obj”作用域中是找不到的,所以JS一直向上遍历,直到全局作用域,最后抛出异常。
So, you can specify your scope directly to fix that:
所以,你可以直接指定你的范围来解决这个问题:
<input value="<%= obj.some_value %>" type="whatever" />
At least it worked for me.
至少它对我有用。
回答by Ngorco
Actually, you can access vars like initial object properties.
实际上,您可以像初始对象属性一样访问变量。
If you'll activate debugger into template, you can find variable "obj", that contains all your data.
如果您将调试器激活到模板中,您可以找到包含所有数据的变量“obj”。
So instead of <%= title %>
you should write <%= obj.title %>
所以<%= title %>
你应该写<%= obj.title %>
回答by Edward Brey
lodash, an underscore replacement, provides a templatefunction with a built-in solution. It has an option to wrap the data in another object to avoid the "with" statement that causes the error.
lodash 是一个下划线替代品,提供了一个带有内置解决方案的模板函数。它可以选择将数据包装在另一个对象中,以避免导致错误的“with”语句。
Sample usage from the API documentation:
API 文档中的示例用法:
// using the `variable` option to ensure a with-statement isn't used in the compiled template
var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
compiled.source;
// → function(data) {
// var __t, __p = '';
// __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
// return __p;
// }
回答by Nicolas Le Thierry d'Ennequin
A very simple solution: you can ensure that your data collection is normalized, i.e. that all properties are present in each object (with a null value if they are unused). A function like this can help:
一个非常简单的解决方案:您可以确保您的数据集合是规范化的,即所有属性都存在于每个对象中(如果未使用,则为空值)。像这样的函数可以帮助:
function normalizeCollection (collection, properties) {
properties = properties || [];
return _.map(collection, function (obj) {
return _.assign({}, _.zipObject(properties, _.fill(Array(properties.length), null)), obj);
});
}
(Note: _.zipObject
and _.fill
are available in recent versions of lodash but not underscore)
(注意:_.zipObject
并且_.fill
在最新版本的 lodash 中可用,但没有下划线)
Use it like this:
像这样使用它:
var coll = [
{ id: 1, name: "Eisenstein"},
{ id: 2 }
];
var c = normalizeCollection(coll, ["id", "name", "age"]);
// Output =>
// [
// { age: null, id: 1, name: "Eisenstein" },
// { age: null, id: 2, name: null }
// ]
Of course, you don't have to transform your data permanently – just invoke the function on the fly as you call your template rendering function:
当然,您不必永久转换数据——只需在调用模板渲染函数时即时调用该函数:
var compiled = _.template(""); // Your template string here
// var output = compiled(data); // Instead of this
var output = compiled(normalizeCollection(data)); // Do this
回答by Daniel Tate
You can abstract @Dmitri's answer further by adding a function to your model and using it in your template.
您可以通过向模型添加函数并在模板中使用它来进一步抽象@Dmitri 的答案。
For example:
例如:
Model :
模型 :
new Model = Backbone.Model.extend({
defaults: {
has_prop: function(prop) {
return _.isUndefined(this[property]) ? false : true;
}
}
});
Template:
模板:
<% if(has_prop('property')) { %>
// Property is available
<% } %>
As the comment in his answer suggests this is more extendable.
正如他的回答中的评论表明这更具可扩展性。