What's the proper way to set a parent property

2019-04-02 05:36发布

I have a JSON file that will create my ParentModel as well as populate the child Records collection.

ParentModel : Backbone.Model.extend({
  initialize: function() {
    this.set({ records: new Records(this.get("records")) });
  }
});

And the Records collection is just a basic Backbone collection that maps to a Record model.

The problem is that I need the child to know about the parent, so each Record model has to have a parent property on it. So for now I've just been adding this to the bottom of the initialize method:

var self = this;
this.get("records").each(function(record) {
  record.set("parent", self);
});

This works fine, but when I'm creating a new record I'd rather not have to remember to include those 4 lines.

This answer says I can override the initialize method to take in additional parameters, but I'm not quite sure how I would get Backbone to automatically pass in the ParentModel to the overridden initialize method. Can anyone provide an example on how to do that?

I've heard of Backbone-relational which might help do what I want, but that's another 23kb to include. If that's the better way to go I'll look at implementing it, but otherwise I'd prefer a simpler solution if one is available.

This needs to work whether I create a new ParentModel record through code, or if it's being automatically created by a JSON feed.

标签: backbone.js
2条回答
【Aperson】
2楼-- · 2019-04-02 06:04

I usually find that moving the structural elements out of the attributes is cleaner so my records and parent properties are on the object, not the attributes. That said, you could take advantage of the different events on the collection and the parent object:

var ParentModel = Backbone.Model.extend({
    initialize: function () {
        _.bindAll(this, 'adoptOne', 'adoptAll');
        this.records = new Records();

        this.on('change:records', function () {
             this.records.reset(this.get('records'));
        });
        this.records.on('reset', this.adoptAll);
        this.records.on('add', this.adoptOne);

        this.records.reset(this.get('records'));
    },

    adoptAll: function () {
       this.records.each(this.adoptOne);
    },
    adoptOne: function (model) {
        model.parent = this;
    }
});

A few tests :

var p = new ParentModel({
    name: "I am the parent",
    records: [{id: 1}, {id: 2}]
});

p.records.add({id: 3});

p.records.each(function (child) {
    console.log(child.get('id')+' '+child.parent.get('name'));
});

p.set({records: [{id: 4}]});

p.records.each(function (child) {
    console.log(child.get('id')+' '+child.parent.get('name'));
});

And a Fiddle http://jsfiddle.net/sPXaZ/

查看更多
Viruses.
3楼-- · 2019-04-02 06:06

Just to be clear, here is a summary of one of your needs (which can be find in the question comments):

For example, if I wanted to center position a Record element, I'd need to know how wide the viewbox is. The only way to know that is to know what the widest record element is. The parent object can tell me that by sorting through its child elements.

It seems to me that your Model have to handle display problematic; display in Backbone is handled by Views. So, I guess you can create a View which listen to both ParentModel and Records.

var RecordView = Backbone.View.extend({
  initialize: function() {
    this.collection.on('sync', this.render, this);
  }
  render: function() {
    var widest = this.model.get('width');
  }
});

var view = new RecordView({model: ParentModel, collection: Records});

And, in my opinion, this is not to the ParentModel to handle the width it take on screen but to its own View. Introducing two Views here seems to be the point.

But I've not the full picture, so, please, if I'm wrong, give me more samples of what you're trying to do.

查看更多
登录 后发表回答