如何根据集合属性设置Backbone模型的默认值

时间:2012-11-05 13:14:31

标签: javascript backbone.js

我需要所有新的MenuItem模型从父系列中获取菜单属性。 这是一个不起作用的基本示例(因为在MenuItem的默认函数中未定义this.collection)

var MenuItem, Menu, menu;

MenuItem = Backbone.Model.extend({
  defaults: function() {
    return {
      menu: this.collection.name
    }
  },

  // Fake Backbone sync
  sync: function(method, model, options) {
    if(typeof model.cid != 'undefined') {
      var cid = model.cid;
      model.unset('cid').set({id:cid}, {silent:true});
    }
    options.success(model);
  }

});

Menu = Backbone.Collection.extend({
  model: MenuItem,
  initialize: function(options) {
    this.name = options.name;
  }
});

menu = new Menu({name: "footer"});

menu.create({title: "Page", url: "/page"}, {
  success: function(model){
    console.log(model.get("menu")) // expect to be "footer"
  }
})

2 个答案:

答案 0 :(得分:1)

我已经设法通过覆盖集合的创建方法来修复它,我仍然不确定这是否是正确的方法。

create: function(attributes, options) {
  return Backbone.Collection.prototype.create.call(
    this,
    _.extend({menu: this.name}, attributes),
    options
  );
}

答案 1 :(得分:1)

对于新模型的每种可能性:

我发现_prepareModel 无证件集合功能中的挂钩效果很好

通用集合

此集合可以原样用于替换默认的Backbone集合。它增加了

  • 要覆盖的新onNewModel功能,它接收新的模型实例和选项
  • 发送相同数据的自定义new-model事件。
var Collection = Backbone.Collection.extend({
    /**
     * Hook into the native _prepareModel to offer a standard hook
     * when new models are added to the collection.
     */
    _prepareModel: function(model, options) {
        model = Collection.__super__._prepareModel.apply(this, arguments);
        if (model) {
            // call our new custom callback
            this.onNewModel(model, options);
            // trigger a new custom event
            this.trigger('new-model', model, options);
        }
        return model;
    },

    // Called when adding a new model to the collection.
    onNewModel: _.noop,
});

你自己的收藏可能是:

var Menu = Collection.extend({
    model: MenuItem,
    initialize: function(models, options) {
        this.name = options.name;
    }
    onNewModel: function(model, options) {
        model.set({ menu: model.get('menu') || this.name });
    },
});

保证modelModel内的Backbone onNewModel实例。

概念证明

// The generic collection, put that in a file and include it once in your project.
var Collection = Backbone.Collection.extend({
  /**
   * Hook into the native _prepareModel to offer a standard hook
   * when new models are added to the collection.
   */
  _prepareModel: function(model, options) {
    model = Collection.__super__._prepareModel.apply(this, arguments);
    if (model) {
      this.onNewModel(model, options);
      this.trigger('new-model', model, options);
    }
    return model;
  },

  // Called when adding a new model to the collection.
  onNewModel: _.noop,
});

// Extend from the generic collection to make your own.
var Menu = Collection.extend({
  initialize: function(models, options) {
    this.name = options.name;
  },
  onNewModel: function(model, options) {
    model.set({
      menu: model.get('menu') || this.name
    });
    
    console.log("onNewModel menu:", model.get('menu'));
  },
});

// then use it
var menu = new Menu([
  // works with bare objects
  {
    title: "Page",
    url: "/page"
  },
  // or Model instances
  new Backbone.Model({
    title: "Other Page"
  })
], {
  name: "footer" // the collection option
});

// Listen to the custom event if you want
Backbone.listenTo(menu, 'new-model', function(model, options) {
    console.log("'new-model' triggered with", model.get('title'));
});

// or other collection methods
menu.add({
  title: "Page",
  menu: "won't be overriden"
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>