Backbone.js 模型fetch()未调用解析

ig9co6j1  于 2022-11-10  发布在  其他
关注(0)|答案(2)|浏览(135)

我有两个函数可以在 Backbone.js 模型上调用fetch。第一个函数使用id创建一个新的模型示例并调用fetch(),第二个函数使用id从集合中检索一个现有的模型示例并调用fetch()。在第一个函数中,模型的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();
        }
    });
};

第二个(不触发解析)

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的示例。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;
            });
        }
    }
});
mo49yndu

mo49yndu1#

parse仅在fetch成功时调用

在 Backbone.js 源代码中,我们可以看到parse函数仅在fetch异步请求成功时被调用。

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仅用于在本地区分模型,不能单独用于提取。
模型的一个特殊属性,cidclient id是一个唯一的标识符,在所有模型首次创建时自动分配给它们。当模型还没有保存到服务器,还没有最终的真实id,但已经需要在UI中可见时,Client id是很方便的。

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

正如Cory Danielson所提到的,如果myItemCollection集合上没有设置model属性,则将调用默认模型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属性,那么无论何时我们在集合上使用addset,我们都将面临同样的问题,即我们的新模型将是Backbone.Model示例,而不是App.Item示例。

避免parse中的副作用

您的parse函数有一些您应该了解的代码味道:

*parse不应该对模型有任何副作用。它应该接收数据并返回转换后的数据,仅此而已。

  • 它应该总是返回数据。在您的例子中,它只在一个条件下返回数据,否则返回undefined
  • 使用**delete是低效的**,最好只返回一个新对象。无论如何,这是另一个你应该避免的副作用。

小心嵌套模型和集合

话虽如此,我发现您在解析中将一个集合嵌套在模型的attributes散列中。我建议您不要使用这种模式,原因如下:

*模型变得非常脆弱,您需要非常小心,始终调用parse: true,并且永远不要在模型之外设置subitems

  • 它会在创建模型后立即为子项创建所有模型,这对于大量模型来说效率很低。延迟初始化子项会有所帮助。
  • 使用**default现在变得更加复杂**,因为您必须记住属性中有一个集合。
    *由于同样的原因,保存模型更加复杂
    *子项中的更改不会触发父模型中的事件

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

wmvff8tz

wmvff8tz2#

有可能你的集合没有使用相同的模型类作为它的模型属性,这就是为什么在那个特定的模型上解析不会被调用的原因。
如果model属性没有设置为您期望的模型,它将不会对该模型调用parse。默认情况下,集合将使用Backbone.Model。

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

你可能会有这样的东西

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

相关问题