【问题标题】:Ignoring undefined data / vars in an underscore template忽略下划线模板中未定义的数据/变量
【发布时间】:2023-03-14 22:57:01
【问题描述】:

还在学习骨干,所以请多多包涵;

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

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

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

Uncaught ReferenceError: some_value is not defined

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

我正在摆弄下划线模板本身,尝试像&lt;%= if(some_value != undefined){ some_value } %&gt; 这样的东西,但这似乎也有点麻烦。

【问题讨论】:

    标签: javascript backbone.js underscore.js


    【解决方案1】:

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

    所以,而不是:

    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"
    

    【讨论】:

    • 如果您尝试访问 model.foo.bar 并且 bar 不存在,这仍然会失败
    • 很高兴知道属性访问不会引发错误。这正是我想要的。我有一个对象,它可能包含一些数据。如果它不存在,我只是希望它被忽略。
    • @regretoverflow 至少您可以检查“属性”是否存在。不同于检查“变量”是否存在。
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      不,

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

      请参阅this discussion 了解它:

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

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

      【讨论】:

        【解决方案4】:

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

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

        这里发生了什么:起初 JS 试图在“obj”中找到你的属性,它是模型(更多关于with 语句)。在“obj”范围内找不到该属性,因此JS向上遍历直到全局范围,最后抛出异常。

        因此,您可以直接指定范围来解决此问题:

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

        至少它对我有用。

        【讨论】:

        • 这个答案和@Dmitriy 的答案是实际的解决方案
        【解决方案5】:

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

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

        所以你应该写&lt;%= obj.title %&gt;而不是&lt;%= title %&gt;

        【讨论】:

          【解决方案6】:

          lodash 是一个下划线替代品,它提供了一个带有内置解决方案的template 函数。它可以选择将数据包装在另一个对象中,以避免导致错误的“with”语句。

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

          【讨论】:

            【解决方案7】:

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

            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 
            

            【讨论】:

              【解决方案8】:

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

              例如:

              型号:

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

              模板:

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2014-11-10
                • 1970-01-01
                • 1970-01-01
                • 2016-04-12
                • 1970-01-01
                • 2011-12-13
                相关资源
                最近更新 更多