如何从车把模板访问主干模型的计算字段?

Posted

技术标签:

【中文标题】如何从车把模板访问主干模型的计算字段?【英文标题】:How to access a calculated field of a backbone model from handlebars template? 【发布时间】:2012-05-25 19:30:57 【问题描述】:

我想从模板访问我在模型 (backbone.js) 中实现的计算字段。 我是否需要始终定义一个助手来执行此操作?

我认为问题与我将模型传递给模板的方式有关。 如果我通过 this.model.toJSON() 我可以访问属性,但不能访问我在其中定义的函数。 如果我直接传递 this.model,我可以访问该函数,但不能访问主干模型的属性。

【问题讨论】:

我认为问题与我将模型传递给模板的方式有关。 【参考方案1】:

始终将this.model.toJSON() 传递给您的模板。

要获得计算值,您需要做的是覆盖模型上的 toJSON 方法。


MyModel = Backbone.Model.extend(

  myValue: function()
    return "this is a calculated value";
  ,

  toJSON: function()
    // get the standard json for the object
    var json = Backbone.Model.prototype.toJSON.apply(this, arguments);

    // get the calculated value
    json.myValue = this.myValue();

    // send it all back
    return json;
  

)

现在您可以从toJSON 返回的JSON 中访问myValue,这意味着您可以在视图中访问它。

正如您所提到的,另一个选项是构建辅助方法并将它们注册到 Handlebars。除非您的某些功能会根据模板的呈现方式和/或传递给模板的数据而发生变化,否则我不会为此烦恼。

【讨论】:

重写 toJSON 有一个缺点:Backbone.sync 使用 toJSON 序列化模型(更准确地说,sync 调用 JSON.stringify 调用 toJSON)所以现在服务器将请参阅myValue,即使它可能并不关心它。这可能是也可能不是问题。【参考方案2】:

我也遇到过同样的问题。 @DerickBailey 是对的,当然,覆盖 toJSON 可以完成这项工作。但它也会泄露到与服务器的通信中(请参阅 muu 对他的回答的评论)。

所以最终,我构建了一个 Backbone 插件来专门处理将数据导出到模板,并以最少的麻烦做到这一点:Backbone.Marionette.Export。它还处理嵌套结构、处理循环引用等。请参阅docs。

这是它的工作原理。将插件文件包含到您的项目中并声明

MyModel = Backbone.Model.extend(

  foo: function () 
      return "I am a calculated value";
  ,

  exportable: "foo"    // <-- this is the one line you have to add

);

如果您是 Marionette 用户,那么此时您已经完成了。 foo 显示在您的模板中,就好像它是模型属性一样。

在普通的 Backbone 视图中,只需在渲染时调用 myModel.export()myCollection.export() 而不是它们的 toJSON 对应项。

对于接受参数的方法,有一个onExport 处理程序。同样,示例位于docs。

【讨论】:

【参考方案3】:

最好的方法是将其添加到您的模型中:

function initialize() 
    this.set("calculatedColumn", function ()  return this.otherColumn; );

主干模型通常在“model.attributes”内部存储实际数据值。这就是为什么当您将模型直接传递给模板时,它只有直接添加到模型的函数而不是任何数据。如果你使用 model.toJSON() 它通常在主干中实现为 _.clone(model.attributes) (参见主干.js)。所以你有数据而不是直接添加到模型中的函数。这就是上述工作的原因 - 您在 model.attributes 上设置函数,而不是在模型对象本身上。不要直接引用model.attributes,使用model.get("calculatedColumn") 和model.set("calculatedColumn", ...)。

所以 model.get("calculatedColumn") 返回一个函数。如果您在车把中使用 calculatedColumn(假设您正在使用车把),它会显示函数返回的值。但是calculatedColumn 不会被发送到服务器,因为backbone 会同步(在backbone.js 中)对model.toJSON 执行JSON.stringify,而JSON.stringify 会忽略函数。如果您希望 JSON.stringify 不忽略该函数(因此,只要在模型上运行 toJSON 时,该函数就会转换为数据值 - 在视图渲染和模型同步期间),请按照 @Derick Bailey 的描述覆盖 model.toJSON。

此外,如果需要,您可以从 Backbone.Model 派生自己的 BaseModel 并覆盖 .toJSON 并从 BaseModel 派生所有模型。然后,您将需要一个通用版本的 .toJSON,它可以应用于任何模型。

【讨论】:

【参考方案4】:

这是另一种可能性:(来自模型初始化)

initialize: function() 
        this.on("change", function () 
            this.set( calculatedColumn: this.get("otherColumn") ,  silent: true );
        );
    ,

Computed properties in Backbone

【讨论】:

以上是关于如何从车把模板访问主干模型的计算字段?的主要内容,如果未能解决你的问题,请参考以下文章

如何将主干视图连接到流星车把模板?

车把或主干将空字符串插入 html

带有主干模板的车把未渲染

仅设置表单提交时输入的字段的主干模型属性

我可以在不直接更新模型的主干表单中拥有表单控件吗?

模型属性未统一命名的主干集合和模板