忽略下划线模板中的未定义数据/变量

时间:2013-03-07 23:16:11

标签: javascript backbone.js underscore.js

仍在学习骨干,所以请耐心等待;

我正在尝试将一个带有空白字段的新模型添加到视图中,但我创建的模板有很多

<input value="<%= some_value %>" type="whatever" />

在获取数据时工作得非常好,它会填充它并且一切顺利。当我想创建一个新的(空白)渲染视图时,会出现问题,它给了我

Uncaught ReferenceError: some_value is not defined

我可以设置defaults(我已经在db中有一些默认值),但这意味着用空格键入40多个;有没有更好的方法处理这个?

我正在摆弄下划线模板本身,尝试像<%= if(some_value != undefined){ some_value } %>这样的东西,但这看起来有点麻烦。

8 个答案:

答案 0 :(得分:24)

将模板数据传递到包装器对象中。缺少属性访问不会引发错误:

所以,而不是:

var template = _.template('<%= foo %><%= bar %>');
var model = {foo:'foo'};
var result = template(model); //-> Error

尝试:

var template = _.template('<%= model.foo %><%= model.bar %>');
var model = {foo:'foo'};
var result = template({model:model}); //-> "foo"

答案 1 :(得分:11)

实际上,您可以在模板中使用arguments

<% if(!_.isUndefined(arguments[0].foo)) { %>
       ...
<% } %>

答案 2 :(得分:10)

否,

由于下划线模板的实现方式,没有实际的修复

请参阅this discussion

  

我担心这只是with(){}在JS中的工作方式。如果未声明变量,则为ReferenceError。我们无能为力,同时保留了其余的模板行为。

你可以完成你正在寻找的东西的唯一方法是用另一个对象包装对象,如建议的其他答案,或者设置默认值。

答案 3 :(得分:5)

如果您检查生成的模板函数的源代码,您将看到如下内容:

with (obj||{}) {
  ...
  // model property is used as variable name
  ...
}

这里发生了什么:首先JS尝试在“obj”中找到你的属性,这是模型(更多关于with语句)。在“obj”范围中找不到此属性,因此JS遍历全局范围并最终抛出异常。

因此,您可以直接指定范围来修复:

<input value="<%= obj.some_value %>" type="whatever" />

至少它对我有用。

答案 4 :(得分:3)

实际上,您可以像初始对象属性一样访问变量。

如果您将调试器激活到模板中,您可以找到包含所有数据的变量“obj”。

因此,您应该写<%= title %>

而不是<%= obj.title %>

答案 5 :(得分:0)

lodash,一个下划线替代品,提供了一个内置解决方案的template功能。它有一个选项可以将数据包装在另一个对象中以避免使用&#34;导致错误的声明。

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;
// }

答案 6 :(得分:0)

一个非常简单的解决方案:您可以确保数据收集已规范化,即每个对象中都存在所有属性(如果未使用,则为空值)。这样的功能可以提供帮助:

function normalizeCollection (collection, properties) {
  properties = properties || [];
  return _.map(collection, function (obj) {
    return _.assign({}, _.zipObject(properties, _.fill(Array(properties.length), null)), obj);
  });
}

(注意:_.zipObject_.fill在最新版本的lodash中可用,但不是下划线)

像这样使用:

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 }
// ]

当然,您不必永久地转换数据 - 只需在调用模板渲染功能时即时调用该函数:

var compiled = _.template(""); // Your template string here
// var output = compiled(data); // Instead of this
var output = compiled(normalizeCollection(data)); // Do this 

答案 7 :(得分:0)

您可以通过向模型添加功能并在模板中使用它来进一步抽象@Dmitri的答案。

例如:

型号:

new Model = Backbone.Model.extend({
    defaults: {
        has_prop: function(prop) {
            return _.isUndefined(this[property]) ? false : true;
        }
    }
});

模板:

<% if(has_prop('property')) { %>
    // Property is available
<% } %>

正如他的回答中的评论所暗示的那样,这是更加可扩展的。