繁体   English   中英

主干模型 fetch() 不调用解析

[英]Backbone model fetch() not calling parse

我有两个函数在 Backbone 模型上调用 fetch。 第一个使用 id 创建模型的新实例并调用 fetch(),第二个使用 id 从集合中检索现有模型实例并调用 fetch()。 在第一个中,模型的解析函数被触发,但在第二个中没有......我不知道为什么。

第一个(触发解析)

App.fetchItemById = function (id) {
    App.myItem = new App.Item({id: id});
    App.myItem.fetch({
        traditional: true,
        data: {
            elements: 'all',
            format:'json',
        },
        success: function(){
            App.myItemView = new App.ItemView({
                el: $('#active-item'),
                model: App.myItem,
            });
            App.myItemView.render();
        }
    });
};

第二个(不触发解析)

App.fetchItemFromCollectionById = function (id) {
    App.myItem = App.myItemCollection.get(id);
    App.myItem.fetch({
        traditional: true,
        data: {
            elements: 'all',
            format:'json',
        },
        success: function(){
            App.myItemView = new App.ItemView({
                el: $('#active-item'),
                model: App.myItem,
            });
            App.myItemView.render();
        }
    });
};

我读过的所有文档都说模型的解析函数总是在获取时调用。

任何人都知道为什么解析不会在第二个触发?

这是模型定义:

App.Item = Backbone.Model.extend({
    urlRoot: '/api/v1/item/',
    defaults: {

    },
    initialize: function(){

    },
    parse : function(response){
        console.log('parsing');
        if (response.stat) {
            if (response.content.subitems) {
                this.set(‘subitems’, new App.SubitemList(response.content.subitems, {parse:true}));
                delete response.content.subitems;
                this
            }

            return response.content;
        } else {
            return response;
        }
    },
});

已修复,感谢 EMILE & Corey - 解决方案如下

原来,当我第一次加载 App.MyItemCollection 时,集合中的模型只是通用模型,没有正确转换为 App.Item 的实例。 在集合定义中添加“model: App.Item”解决了这个问题。 见下文:

原版

App.ItemList = Backbone.Collection.extend({
    url: '/api/v1/item/',
    parse : function(response){
        if (response.stat) {
            return _.map(response.content, function(model, id) {
                model.id = id;
                return model;
            });
        }
    }
});

更新,已解决的问题

App.ItemList = Backbone.Collection.extend({
    url: '/api/v1/item/',
    model: App.Item,
    parse : function(response){
        if (response.stat) {
            return _.map(response.content, function(model, id) {
                model.id = id;
                return model;
            });
        }
    }
});

仅在成功fetch调用parse

Backbone 源码中,我们可以看到parse函数只有在fetch async 请求成功时才会被调用。

fetch: function(options) {
  options = _.extend({parse: true}, options);
  var model = this;
  var success = options.success;

  // The success callback is replaced with this one.
  options.success = function(resp) {
    // parse is called only if the fetch succeeded
    var serverAttrs = options.parse ? model.parse(resp, options) : resp;
    // ...snip...
    // then the provided callback, if any, is called
    if (success) success.call(options.context, model, resp, options);

  };
  wrapError(this, options);
  return this.sync('read', this, options);
},

parse文档说:

每当服务器在fetchsave返回模型的数据时,就会调用parse

假设fetch失败,服务器不会返回任何模型数据,因此不会调用 parse。

为了对现有模型进行成功fetch ,默认行为要求模型在其attributes哈希中具有一个id

cid仅用于在本地区分模型,不能单独用于获取。

模型的一个特殊属性, cid客户端 id是一个唯一标识符,它在首次创建时自动分配给所有模型。 当模型尚未保存到服务器时,客户端 id 很方便,并且还没有最终的真实 id,但已经需要在 UI 中可见。


确保集合使用我们自己的模型

正如Cory Danielson提到的,如果model属性未在myItemCollection集合上设置,则将myItemCollection默认模型parse ,而不是您的App.Item模型的parse

模型不应该在parse函数中实例化,因为它是集合的责任。

App.ItemList = Backbone.Collection.extend({
    model: App.Item, // make sure to set this property
    url: '/api/v1/item/',
    parse : function(response){
        if (response.stat) {
            return _.map(response.content, function(model, id) {
                model.id = id;
                return model;
            });
        }
    }
});

如果我们没有在集合上设置model属性,那么无论何时我们在set上使用addset ,我们都会面临同样的问题,我们的新模型将是Backbone.Model实例而不是App.Item实例。


避免parse的副作用

你的parse函数有一些你应该知道的代码味道:

  • parse不应该对模型产生任何副作用 它应该接收数据并返回转换后的数据,就是这样。
  • 它应该总是返回数据 在您的情况下,它仅在条件下返回数据,否则返回undefined
  • 使用delete效率低下,最好只返回一个新对象。 无论如何,这是您应该避免的另一个副作用。

小心嵌套模型和集合

话虽如此,我看到您在解析中的模型的attributes哈希中嵌套了一个集合。 出于以下几个原因,我建议不要采用这种模式:

  • 模型变得非常脆弱,您需要非常小心地始终调用parse: true ,并且永远不要在模型之外设置subitems
  • 它在创建模型后立即为子项创建所有模型,这对于许多模型来说效率低下。 延迟初始化子项会有所帮助。
  • 使用default值现在更加复杂,因为您必须记住属性中有一个集合。
  • 出于同样的原因,保存模型更加复杂
  • 子项内的更改不会触发父模型中的事件

我已经在这里回答了这些问题有多种解决方案:

您的集合可能没有为其模型属性使用相同的模型类。 这就是为什么不会调用对该特定模型的解析。

如果model属性未设置为您期望的模型,则不会对该模型调用 parse。 默认情况下,集合将使用 Backbone.Model。

MyItemCollection = Backbone.Collection.extend({
    model: App.Item
});

你可能拥有的是这样的

MyItemCollection = Backbone.Collection.extend({
    model: Backbone.Model.extend({
        urlRoot: '/api/v1/item/'
    })
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM