Nested Models in Backbone.js, how to approach

2019-01-12 14:38发布

I've got the following JSON provided from a server. With this, I want to create a model with a nested model. I am unsure of which is the way to achieve this.

//json
[{
    name : "example",
    layout : {
        x : 100,
        y : 100,
    }
}]

I want these to be converted to two nested backbone models with the following structure:

// structure
Image
    Layout
...

So I define the Layout model like so:

var Layout = Backbone.Model.extend({});

But which of the two (if any) techniques below should I use to define the Image model? A or B below?

A

var Image = Backbone.Model.extend({
    initialize: function() {
        this.set({ 'layout' : new Layout(this.get('layout')) })
    }
});

or, B

var Image = Backbone.Model.extend({
    initialize: function() {
        this.layout = new Layout( this.get('layout') );
    }
});

12条回答
\"骚年 ilove
2楼-- · 2019-01-12 15:04

I use Backbone DeepModel plugin for nested models and attributes.

https://github.com/powmedia/backbone-deep-model

You can bind to change events 'n levels deep. for example: model.on('change:example.nestedmodel.attribute', this.myFunction);

查看更多
老娘就宠你
3楼-- · 2019-01-12 15:04

Use backbone-forms

It supports nested forms, models and toJSON. ALL NESTED

var Address = Backbone.Model.extend({
    schema: {
    street:  'Text'
    },

    defaults: {
    street: "Arteaga"
    }

});


var User = Backbone.Model.extend({
    schema: {
    title:      { type: 'Select', options: ['Mr', 'Mrs', 'Ms'] },
    name:       'Text',
    email:      { validators: ['required', 'email'] },
    birthday:   'Date',
    password:   'Password',
    address:    { type: 'NestedModel', model: Address },
    notes:      { type: 'List', itemType: 'Text' }
    },

    constructor: function(){
    Backbone.Model.apply(this, arguments);
    },

    defaults: {
    email: "x@x.com"
    }
});

var user = new User();

user.set({address: {street: "my other street"}});

console.log(user.toJSON()["address"]["street"])
//=> my other street

var form = new Backbone.Form({
    model: user
}).render();

$('body').append(form.el);
查看更多
我想做一个坏孩纸
4楼-- · 2019-01-12 15:05

If you don't want to add yet another framework, you might consider creating a base class with overridden set and toJSON and use it like this:

// Declaration

window.app.viewer.Model.GallerySection = window.app.Model.BaseModel.extend({
  nestedTypes: {
    background: window.app.viewer.Model.Image,
    images: window.app.viewer.Collection.MediaCollection
  }
});

// Usage

var gallery = new window.app.viewer.Model.GallerySection({
    background: { url: 'http://example.com/example.jpg' },
    images: [
        { url: 'http://example.com/1.jpg' },
        { url: 'http://example.com/2.jpg' },
        { url: 'http://example.com/3.jpg' }
    ],
    title: 'Wow'
}); // (fetch will work equally well)

console.log(gallery.get('background')); // window.app.viewer.Model.Image
console.log(gallery.get('images')); // window.app.viewer.Collection.MediaCollection
console.log(gallery.get('title')); // plain string

You'll need BaseModel from this answer (available, if you fancy, as a gist).

查看更多
5楼-- · 2019-01-12 15:06

I realize I'm late to this party, but we recently released a plugin to deal with exactly this scenario. It's called backbone-nestify.

So your nested model remains unchanged:

var Layout = Backbone.Model.extend({...});

Then use the plugin when defining the containing model (using Underscore.extend):

var spec = {
    layout: Layout
};
var Image = Backbone.Model.extend(_.extend({
    // ...
}, nestify(spec));

After that, assuming you have a model m which is an instance of Image, and you've set the JSON from the question on m, you can do:

m.get("layout");    //returns the nested instance of Layout
m.get("layout|x");  //returns 100
m.set("layout|x", 50);
m.get("layout|x");  //returns 50
查看更多
Viruses.
6楼-- · 2019-01-12 15:12

I'm not sure Backbone itself has a recommended way to do this. Does the Layout object have its own ID and record in the back end database? If so you can make it its own Model as you have. If not, you can just leave it as a nested document, just make sure you convert it to and from JSON properly in the save and parse methods. If you do end up taking an approach like this, I think your A example is more consistent with backbone since set will properly update attributes, but again I'm not sure what Backbone does with nested models by default. It's likely you'll need some custom code to handle this.

查看更多
在下西门庆
7楼-- · 2019-01-12 15:14

CoffeeScript version of rycfung's beautiful answer:

class ImageModel extends Backbone.Model
  model: {
      layout: LayoutModel
  }

  parse: (response) =>
    for propName,propModel of @model
      response[propName] = new propModel( response[propName], {parse:true, parentModel:this} )

    return response

Ain't that sweet? ;)

查看更多
登录 后发表回答