简体   繁体   English

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

[英]Backbone model fetch() not calling parse

I have two functions that call fetch on a Backbone model.我有两个函数在 Backbone 模型上调用 fetch。 The first one creates a new instance of a model using an id and calls fetch(), the second one retrieves an existing model instance from a collection using id and calls fetch().第一个使用 id 创建模型的新实例并调用 fetch(),第二个使用 id 从集合中检索现有模型实例并调用 fetch()。 In the first one, the model's parse function is triggered, but not on the second one...and I don't know why.在第一个中,模型的解析函数被触发,但在第二个中没有......我不知道为什么。

First one (triggers parse)第一个(触发解析)

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();
        }
    });
};

Second one (doesn't trigger parse)第二个(不触发解析)

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();
        }
    });
};

All of the documentation I've read says that the model's parse function is ALWAYS called on fetch.我读过的所有文档都说模型的解析函数总是在获取时调用。

Anyone know why parse isn't triggered on the second one?任何人都知道为什么解析不会在第二个触发?

Here's the model definition:这是模型定义:

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;
        }
    },
});

FIXED, THANKS TO EMILE & COREY - SOLUTION BELOW已修复,感谢 EMILE & Corey - 解决方案如下

Turns out, when I first load the App.MyItemCollection, the models in the collection were just generic models, not correctly cast as instances of App.Item.原来,当我第一次加载 App.MyItemCollection 时,集合中的模型只是通用模型,没有正确转换为 App.Item 的实例。 Adding "model: App.Item" to the collection definition solved the problem.在集合定义中添加“model: App.Item”解决了这个问题。 See below:见下文:

ORIGINAL原版

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

UPDATED, SOLVED PROBLEM更新,已解决的问题

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

parse is only called on successful fetch仅在成功fetch调用parse

In the Backbone source , we can see that the parse function is only called when the fetch async request succeeds.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);
},

The documentation on parse says: parse文档说:

parse is called whenever a model's data is returned by the server, in fetch , and save .每当服务器在fetchsave返回模型的数据时,就会调用parse

Supposing that fetch fails, no model data is returned by the server, so parse won't be called.假设fetch失败,服务器不会返回任何模型数据,因此不会调用 parse。

For fetch to succeed with an existing model, the default behavior requires that the model has an id in its attributes hash.为了对现有模型进行成功fetch ,默认行为要求模型在其attributes哈希中具有一个id

The cid is only used to distinguish models locally and won't work on its own for a fetch. cid仅用于在本地区分模型,不能单独用于获取。

A special property of models, the cid or client id is a unique identifier automatically assigned to all models when they're first created.模型的一个特殊属性, cid客户端 id是一个唯一标识符,它在首次创建时自动分配给所有模型。 Client ids are handy when the model has not yet been saved to the server, and does not yet have its eventual true id, but already needs to be visible in the UI.当模型尚未保存到服务器时,客户端 id 很方便,并且还没有最终的真实 id,但已经需要在 UI 中可见。


Make sure a collection uses our own model确保集合使用我们自己的模型

As mentioned by Cory Danielson , if the model property is not set on the myItemCollection collection, the default model parse will be called, not your App.Item model's parse .正如Cory Danielson提到的,如果model属性未在myItemCollection集合上设置,则将myItemCollection默认模型parse ,而不是您的App.Item模型的parse

Models shouldn't be instantiated in the parse function as it's a responsibility of the collection.模型不应该在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;
            });
        }
    }
});

If we don't set the model property on the collection, anytime we'll use add or set on the collection, we'll be facing the same problem where our new models will be Backbone.Model instances instead of App.Item instances.如果我们没有在集合上设置model属性,那么无论何时我们在set上使用addset ,我们都会面临同样的问题,我们的新模型将是Backbone.Model实例而不是App.Item实例。


Avoid side-effects in parse避免parse的副作用

Your parse function has some code smell you should know about:你的parse函数有一些你应该知道的代码味道:

  • parse shouldn't have any side-effects on the model. parse不应该对模型产生任何副作用 It should receive data and return transformed data, that's it.它应该接收数据并返回转换后的数据,就是这样。
  • It should always return data .它应该总是返回数据 In your case, it only returns data under a condition, and returns undefined otherwise.在您的情况下,它仅在条件下返回数据,否则返回undefined
  • Using delete is inefficient and it's better to just return a new object.使用delete效率低下,最好只返回一个新对象。 Anyway, that's another side-effect that you should avoid.无论如何,这是您应该避免的另一个副作用。

Be careful with nested models and collections小心嵌套模型和集合

That being said, I see that you're nesting a collection within the attributes hash of your model, within the parsing.话虽如此,我看到您在解析中的模型的attributes哈希中嵌套了一个集合。 I would advise against that pattern for a couple reasons:出于以下几个原因,我建议不要采用这种模式:

  • The model becomes really fragile , where you need to be really careful to always call parse: true , and never set subitems outside the model.模型变得非常脆弱,您需要非常小心地始终调用parse: true ,并且永远不要在模型之外设置subitems
  • It creates all the models for the subitems as soon as a model is created, which is inefficient with a lot of models.它在创建模型后立即为子项创建所有模型,这对于许多模型来说效率低下。 Lazy initializing the sub-items would help.延迟初始化子项会有所帮助。
  • Using the default is now more complex since you have to keep in mind that there's a collection within the attributes.使用default值现在更加复杂,因为您必须记住属性中有一个集合。
  • Saving the model is more complex for the same reason.出于同样的原因,保存模型更加复杂
  • Changes within the subitems won't trigger events in the parent model.子项内的更改不会触发父模型中的事件

There are multiple solutions to these which I already answered here:我已经在这里回答了这些问题有多种解决方案:

It's possible that your collection isn't using the same model class for it's model property.您的集合可能没有为其模型属性使用相同的模型类。 That's why parse on that particular model would not be called.这就是为什么不会调用对该特定模型的解析。

If the model property isn't set to the model that you expect, it's not going to call parse on that model.如果model属性未设置为您期望的模型,则不会对该模型调用 parse。 By default the collection will use a Backbone.Model.默认情况下,集合将使用 Backbone.Model。

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

What you might have is something like this你可能拥有的是这样的

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