119

サーバーから提供された次の JSON を取得しました。これで、ネストされたモデルでモデルを作成したいと思います。これを達成する方法がどれなのかわかりません。

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

これらを、次の構造を持つ 2 つのネストされたバックボーン モデルに変換したいと考えています。

// structure
Image
    Layout
...

したがって、レイアウトモデルを次のように定義します。

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

しかし、Image モデルを定義するには、以下の 2 つの手法 (ある場合) のうちどれを使用すればよいでしょうか? 以下のAまたはB?

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

または、 B

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

12 に答える 12

99

バックボーンアプリケーションを作成しているときに、まったく同じ問題が発生します。埋め込み/ネストされたモデルを処理する必要があります。非常にエレガントな解決策だと思ったいくつかの調整を行いました。

はい、解析メソッドを変更してオブジェクト内の属性を変更することはできますが、それはすべて実際にはかなり保守不可能なコードIMOであり、解決策というよりはハックのように感じます。

これがあなたの例のために私が提案するものです:

まず、そのようにレイアウトモデルを定義します。

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

次に、画像モデルを示します。

var imageModel = Backbone.Model.extend({

    model: {
        layout: layoutModel,
    },

    parse: function(response){
        for(var key in this.model)
        {
            var embeddedClass = this.model[key];
            var embeddedData = response[key];
            response[key] = new embeddedClass(embeddedData, {parse:true});
        }
        return response;
    }
});

モデル自体を改ざんしていないことに注意してください。解析メソッドから目的のオブジェクトを返すだけです。

これにより、サーバーから読み取るときにネストされたモデルの構造が保証されます。さて、適切なモデルを使用してネストされたモデルを明示的に設定することは理にかなっていると思うので、ここでは保存や設定が実際には処理されないことに気付くでしょう。

そのようです:

image.set({layout : new Layout({x: 100, y: 100})})

また、ネストされたモデルで実際にparseメソッドを呼び出しているのは、次の呼び出しであることに注意してください。

new embeddedClass(embeddedData, {parse:true});

フィールドには、必要な数のネストされたモデルを定義できますmodel

もちろん、ネストされたモデルを独自のテーブルに保存するところまで行きたい場合。これでは十分ではありません。ただし、オブジェクト全体を読み取って保存する場合は、このソリューションで十分です。

于 2012-03-28T09:40:37.923 に答える
16

このコードは、Peter Lyon によるパースの再定義の提案の例として投稿しています。私は同じ質問をしましたが、これは私にとってはうまくいきました(Railsバックエンドで)。このコードは Coffeescript で書かれています。よく知らない人のために、いくつかのことを明確にしました。

class AppName.Collections.PostsCollection extends Backbone.Collection
  model: AppName.Models.Post

  url: '/posts'

  ...

  # parse: redefined to allow for nested models
  parse: (response) ->  # function definition
     # convert each comment attribute into a CommentsCollection
    if _.isArray response
      _.each response, (obj) ->
        obj.comments = new AppName.Collections.CommentsCollection obj.comments
    else
      response.comments = new AppName.Collections.CommentsCollection response.comments

    return response

または、JSで

parse: function(response) {
  if (_.isArray(response)) {
    return _.each(response, function(obj) {
      return obj.comments = new AppName.Collections.CommentsCollection(obj.comments);
    });
  } else {
    response.comments = new AppName.Collections.CommentsCollection(response.comments);
  }
  return response;
};
于 2011-11-23T07:46:16.327 に答える
12

Backbone-associationBackbone.AssociatedModelから使用:

    var Layout = Backbone.AssociatedModel.extend({
        defaults : {
            x : 0,
            y : 0
        }
    });
    var Image = Backbone.AssociatedModel.extend({
        relations : [
            type: Backbone.One,
            key : 'layout',
            relatedModel : Layout          
        ],
        defaults : {
            name : '',
            layout : null
        }
    });
于 2012-09-23T04:08:23.777 に答える
11

バックボーン自体にこれを行うための推奨される方法があるかどうかはわかりません。レイアウト オブジェクトはバックエンド データベースに独自の ID とレコードを持っていますか? もしそうなら、あなたが持っているようにそれを独自のモデルにすることができます。saveそうでない場合は、ネストされたドキュメントのままにしておくことができます。メソッドとメソッドで JSON との間で適切に変換するようにしてくださいparse。このようなアプローチを取ることになった場合、適切に更新されるため、 A の例はバックボーンとより一貫していると思いますが、バックボーンがデフォルトでネストされたモデルで何をするかはわかりません。これを処理するには、カスタム コードが必要になる可能性があります。setattributes

于 2011-06-30T14:15:09.037 に答える
8

物事をシンプルに保ちたい場合は、オプション B を使用します。

別の適切なオプションは、Backbone-Relationalを使用することです。次のように定義するだけです。

var Image = Backbone.Model.extend({
    relations: [
        {
            type: Backbone.HasOne,
            key: 'layout',
            relatedModel: 'Layout'
        }
    ]
});
于 2013-02-04T01:47:31.563 に答える
6

ネストされたモデルと属性にはBackboneDeepModelプラグインを使用します。

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

バインドして、イベントのnレベルを深く変更できます。例えば: model.on('change:example.nestedmodel.attribute', this.myFunction);

于 2012-09-23T04:17:01.537 に答える
5

rycfungの美しい答えのCoffeeScriptバージョン:

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

甘くない?;)

于 2013-08-28T00:08:23.840 に答える
2

私はこのパーティーに遅れていることを認識していますが、最近、まさにこのシナリオに対処するためのプラグインをリリースしました。これはbackbone-nestifyと呼ばれます。

したがって、ネストされたモデルは変更されません。

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

次に、包含モデルを定義するときにプラグインを使用します ( Underscore.extendを使用):

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

その後、mのインスタンスであるモデルがありImage、 の質問から JSON を設定したと仮定するとm、次のことができます。

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
于 2014-02-24T23:59:35.717 に答える
2

バックボーン フォームを使用する

ネストされたフォーム、モデル、および toJSON をサポートします。すべて入れ子

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);
于 2014-03-06T08:13:24.613 に答える
1

さらに別のフレームワークを追加したくない場合は、オーバーライドされた基本クラスを作成し、次のように使用することを検討してsetくださいtoJSON

// 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

BaseModelこの回答から必要になります(必要に応じて、 gist として利用できます)。

于 2013-09-24T18:49:43.107 に答える