骨干模型fetch()不调用parse

时间:2017-11-09 21:44:47

标签: javascript backbone.js

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

第一个(触发解析)

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

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

任何人都知道为什么在第二个问题上没有触发解析?

这是模型定义:

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

固定,感谢EMILE& COREY - 以下解决方案

事实证明,当我第一次加载App.MyItemCollection时,集合中的模型只是通用模型,没有正确地转换为App.Item的实例。添加"模型:App.Item"收集定义解决了问题。见下文:

ORIGINAL

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

更新,已解决的问题

createMovie(movie: Movie): void {
  this._dataService.createMovie<Movie>({'name': 'Star Wars'})
  .subscribe((data) => this.movies.push(data),
  error => () => {
      'something went wrong';
  },
  () => {
      // console.log(this.movies);
  });
}

2 个答案:

答案 0 :(得分:2)

仅在成功parse 时调用

fetch

Backbone source中,我们可以看到仅在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);
},

documentation on parse说:

  只要服务器返回模型的数据,就会调用

parse ,   fetchsave

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

要使fetch成功使用现有模型,默认行为要求模型在其id哈希中具有attributes

cid仅用于在本地区分模型,并且不会自行进行提取。

  

模特的特殊属性, cid 客户ID 是唯一的   标识符在首次显示时自动分配给所有模型   创建。当模型尚未保存到时,客户端ID很方便   服务器,并且还没有最终的真实ID   需要在用户界面中显示。

确保您的收藏集使用您的模型

作为mentioned by Cory Danielson,如果myItemCollection集合中未设置model property,则会调用默认模型parse,而不是App.Item模型&# 39; s 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 property,那么只要您在集合中使用addset,您就会面对同样的问题,您的新模型将是Backbone.Model个实例,而不是App.Item个实例。

避免parse

中的副作用

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

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

小心嵌套模型和集合

话虽这么说,我看到你在解析中将一个集合嵌套在模型的attributes哈希中。我会建议反对这种模式有几个原因:

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

我已经在以下答案中列出了多种解决方案:

答案 1 :(得分:0)

您的收藏品可能不会使用相同的模型类别来处理它的模型属性。这就是解析该特定模型的原因。

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

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

你可能拥有的是这样的东西

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