Backbone.js में नेस्टेड मॉडल, कैसे अप्रोच करें


117

मुझे निम्नलिखित JSON एक सर्वर से प्रदान किया गया है। इसके साथ, मैं एक नेस्टेड मॉडल के साथ एक मॉडल बनाना चाहता हूं। मैं अनिश्चित हूं कि इसे प्राप्त करने का तरीका क्या है।

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

मैं चाहता हूं कि इन्हें निम्नलिखित संरचना के साथ दो नेस्टेड रीढ़ मॉडल में बदला जाए:

// structure
Image
    Layout
...

इसलिए मैं लेआउट मॉडल को इस तरह परिभाषित करता हूं:

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

लेकिन छवि मॉडल को परिभाषित करने के लिए नीचे दी गई दोनों में से कौन सी (यदि कोई है) तकनीक का उपयोग करना चाहिए? A या B नीचे?

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

या, बी

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

जवाबों:


98

मेरे बैकबोन एप्लिकेशन को लिखते समय मेरे पास एक ही मुद्दा है। एम्बेडेड / नेस्टेड मॉडल से निपटने के लिए। मैंने कुछ ट्विक्स किए जो मुझे लगा कि एक बहुत ही सुंदर समाधान है।

हां, आप ऑब्जेक्ट में चारों ओर की विशेषताओं को बदलने के लिए पार्स विधि को संशोधित कर सकते हैं, लेकिन यह सब वास्तव में बहुत ही अचूक कोड आईएमओ है, और एक समाधान की तुलना में अधिक हैक लगता है।

यहाँ मैं आपके उदाहरण के लिए सुझाव देता हूं:

पहले अपने लेआउट मॉडल को इस तरह परिभाषित करें।

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

यह भी ध्यान रखें कि आप वास्तव में कॉल करके अपने नेस्टेड मॉडल में पार्स विधि को लागू कर रहे हैं:

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

आप modelक्षेत्र में कई नेस्टेड मॉडल को परिभाषित कर सकते हैं जितनी आपको आवश्यकता है।

बेशक, यदि आप नेस्टेड मॉडल को अपनी तालिका में सहेजने के रूप में दूर तक जाना चाहते हैं। यह पर्याप्त नहीं होगा। लेकिन समग्र रूप से ऑब्जेक्ट को पढ़ने और सहेजने के मामले में, इस समाधान को पर्याप्त होना चाहिए।


4
यह अच्छा है .. अन्य दृष्टिकोणों की तुलना में इसके दूर के क्लीनर के रूप में स्वीकृत उत्तर होना चाहिए। केवल सुझाव है कि मुझे आपकी कक्षाओं के पहले अक्षर को बड़ा करना है जो पठनीयता के लिए Backbone.Model का विस्तार करता है .. अर्थात ImageModel और LayoutModel
स्टीफन

1
@StephenHandley टिप्पणी और आपके सुझाव के लिए धन्यवाद। जानकारी के लिए, मैं वास्तव में आवश्यकता के संदर्भ में इसका उपयोग कर रहा हूं। इसलिए, कैपिटलाइज़ेशन मामले का जवाब देने के लिए, वास्तव में var 'imageModel' कोJJS की आवश्यकता होती है। और मॉडल का संदर्भ निम्नलिखित निर्माण द्वारा समझाया जाएगा: define(['modelFile'], function(MyModel){... do something with MyModel}) लेकिन आप सही हैं। आपके द्वारा सुझाए गए सम्मेलन द्वारा मॉडल का संदर्भ देना मेरी आदत है।
रिक्फंग

@ याकूब क्षमा करें, एक टाइपो था। प्रतिक्रिया होनी चाहिए थी। मैंने इसे ठीक कर दिया है, इंगित करने के लिए धन्यवाद।
रायक

2
अच्छा! मैं इसे Backbone.Model.prototype.parseफ़ंक्शन में जोड़ने की सलाह देता हूं । फिर, आपके सभी मॉडलों को सबमॉडल ऑब्जेक्ट प्रकार (आपके "मॉडल" विशेषता) में परिभाषित करना है।
जसोप

1
ठंडा! मैं ऐसा ही कुछ कर रहा हूं (यह जवाब मिलने के बाद निश्चित रूप से और अफसोस के साथ)। मैंने इसे यहां लिखा है: blog.untrod.com/2013/08/declarative-approach-to-nesting.html बड़ा अंतर यह है कि गहराई से नेस्टेड मॉडल के लिए मैं रूट / पैरेंट मॉडल में एक बार में पूरे मैपिंग की घोषणा करता हूं, और कोड इसे वहां से ले जाता है और पूरे मॉडल को नीचे चला जाता है, संबंधित वस्तुओं को बैकबोन संग्रह और मॉडल में हाइड्रेट करता है। लेकिन वास्तव में एक समान दृष्टिकोण।
क्रिस क्लार्क

16

मैं इस कोड को पीटर लियोन द्वारा पार्स को फिर से परिभाषित करने के सुझाव के उदाहरण के रूप में पोस्ट कर रहा हूं। मेरे पास एक ही सवाल था और यह मेरे लिए काम कर रहा था (एक रेल बैकएंड के साथ)। यह कोड कॉफ़ीस्क्रिप्ट में लिखा गया है। मैंने इससे अपरिचित लोगों के लिए कुछ बातें स्पष्ट कीं।

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

या, जेएस में

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

उदाहरण कोड और ओवरराइडिंग पार्स का सुझाव देने के लिए सहारा। धन्यवाद!
एडवर्ड एंडरसन

11
असली जेएस में आपका जवाब अच्छा होगा
जेसन

6
कॉफ़ीस्क्रिप्ट संस्करण के लिए खुश, धन्यवाद। दूसरों के लिए, js2cfish.org
ABCD.ca

16
यदि प्रश्न वास्तविक जेएस है, तो एक उत्तर भी होना चाहिए।
मैनुअल हर्नान्डेज़

12

बैकबोन-एसोसिएशनBackbone.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
        }
    });

अच्छा समाधान है। इसी तरह की एक परियोजना भी है: github.com/PaulUithol/Backbone-relational
michaelok

11

मुझे यकीन नहीं है कि बैकबोन के पास ऐसा करने के लिए अनुशंसित तरीका है। क्या बैक-एंड डेटाबेस में लेआउट ऑब्जेक्ट का अपना आईडी और रिकॉर्ड है? यदि ऐसा है तो आप इसे अपना मॉडल बना सकते हैं जैसा आपके पास है। यदि नहीं, तो आप इसे केवल एक नेस्टेड दस्तावेज़ के रूप में छोड़ सकते हैं, बस यह सुनिश्चित करें कि आप इसे JSON से saveऔर parseविधियों में ठीक से परिवर्तित कर सकते हैं । यदि आप इस तरह से एक दृष्टिकोण लेना समाप्त करते हैं, तो मुझे लगता है कि आपका उदाहरण बैकबोन के साथ अधिक सुसंगत है क्योंकि setठीक से अपडेट होगा attributes, लेकिन फिर से मुझे यकीन नहीं है कि बैकबोन डिफ़ॉल्ट रूप से नेस्टेड मॉडल के साथ क्या करता है। यह संभव है कि आपको इसे संभालने के लिए कुछ कस्टम कोड की आवश्यकता होगी।


आह! क्षमा करें, यह newऑपरेटर गायब था । मैंने इस गलती को ठीक करने के लिए इसे संपादित किया है।
रोस

ओह, तो मैंने आपके सवाल का गलत मतलब निकाला। मैं अपना जवाब अपडेट करूंगा।
पीटर लियोन

8

यदि आप चीजों को सरल रखना चाहते हैं तो मैं विकल्प बी के साथ जाऊंगा।

एक और अच्छा विकल्प बैकबोन-रिलेशनल का उपयोग करना होगा । आप कुछ इस तरह परिभाषित करेंगे:

var Image = Backbone.Model.extend({
    relations: [
        {
            type: Backbone.HasOne,
            key: 'layout',
            relatedModel: 'Layout'
        }
    ]
});

+1 बैकबोन-रिलेटेन्शनल काफी स्थापित लगता है: खुद की वेबसाइट, 1.6k स्टार, 200+ कांटे।
रॉस

6

मैं नेस्टेड मॉडल और विशेषताओं के लिए बैकबोन डीपमॉडल प्लगइन का उपयोग करता हूं।

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

आप घटनाओं के n स्तरों को गहरे में बदलने के लिए बाध्य कर सकते हैं। उदाहरण के लिए: model.on('change:example.nestedmodel.attribute', this.myFunction);


5

कॉफी के संस्करण का रीफफंग का सुंदर जवाब:

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

कि मिठाई नहीं है? ;)


11
मैं अपने जावास्क्रिप्ट में चीनी नहीं लेता
रॉस

2

मेरे पास एक ही मुद्दा था और मैं rycfung के उत्तर में कोड के साथ प्रयोग कर रहा हूं , जो एक महान सुझाव है।
अगर, हालांकि, आप नहीं करना चाहते setनेस्टेड मॉडल सीधे, या लगातार पास करना चाहते हैं नहीं है {parse: true}में options, एक और दृष्टिकोण को फिर से परिभाषित करने के लिए किया जाएगा setही।

में रीढ़ 1.0.0 , setमें कहा जाता है constructor, unset, clear, fetchऔर save

निम्नलिखित मॉडल पर विचार करें , सभी मॉडलों के लिए जिन्हें घोंसले के मॉडल और / या संग्रह की आवश्यकता है।

/** Compound supermodel */
var CompoundModel = Backbone.Model.extend({
    /** Override with: key = attribute, value = Model / Collection */
    model: {},

    /** Override default setter, to create nested models. */
    set: function(key, val, options) {
        var attrs, prev;
        if (key == null) { return this; }

        // Handle both `"key", value` and `{key: value}` -style arguments.
        if (typeof key === 'object') {
            attrs = key;
            options = val;
        } else {
            (attrs = {})[key] = val;
        }

        // Run validation.
        if (options) { options.validate = true; }
        else { options = { validate: true }; }

        // For each `set` attribute, apply the respective nested model.
        if (!options.unset) {
            for (key in attrs) {
                if (key in this.model) {
                    if (!(attrs[key] instanceof this.model[key])) {
                        attrs[key] = new this.model[key](attrs[key]);
                    }
                }
            }
        }

        Backbone.Model.prototype.set.call(this, attrs, options);

        if (!(attrs = this.changedAttributes())) { return this; }

        // Bind new nested models and unbind previous nested models.
        for (key in attrs) {
            if (key in this.model) {
                if (prev = this.previous(key)) {
                    this._unsetModel(key, prev);
                }
                if (!options.unset) {
                    this._setModel(key, attrs[key]);
                }
            }
        }
        return this;
    },

    /** Callback for `set` nested models.
     *  Receives:
     *      (String) key: the key on which the model is `set`.
     *      (Object) model: the `set` nested model.
     */
    _setModel: function (key, model) {},

    /** Callback for `unset` nested models.
     *  Receives:
     *      (String) key: the key on which the model is `unset`.
     *      (Object) model: the `unset` nested model.
     */
    _unsetModel: function (key, model) {}
});

ध्यान दें कि model, _setModelऔर _unsetModelउद्देश्य पर खाली छोड़ दिया जाता है। अमूर्त के इस स्तर पर आप शायद कॉलबैक के लिए किसी भी उचित कार्यों को परिभाषित नहीं कर सकते हैं। हालाँकि, आप उन्हें उन सबमॉडल्स में ओवरराइड करना चाह सकते हैं जो विस्तार करते हैं CompoundModel
उदाहरण के लिए, श्रोताओं को बांधने और changeघटनाओं के प्रचार के लिए वे कॉलबैक उपयोगी हैं ।


उदाहरण:

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

var Image = CompoundModel.extend({
    defaults: function () {
        return {
            name: "example",
            layout: { x: 0, y: 0 }
        };
    },

    /** We need to override this, to define the nested model. */
    model: { layout: Layout },

    initialize: function () {
        _.bindAll(this, "_propagateChange");
    },

    /** Callback to propagate "change" events. */
    _propagateChange: function () {
        this.trigger("change:layout", this, this.get("layout"), null);
        this.trigger("change", this, null);
    },

    /** We override this callback to bind the listener.
     *  This is called when a Layout is set.
     */
    _setModel: function (key, model) {
        if (key !== "layout") { return false; }
        this.listenTo(model, "change", this._propagateChange);
    },

    /** We override this callback to unbind the listener.
     *  This is called when a Layout is unset, or overwritten.
     */
    _unsetModel: function (key, model) {
        if (key !== "layout") { return false; }
        this.stopListening();
    }
});

इसके साथ, आपके पास स्वचालित नेस्टेड मॉडल निर्माण और ईवेंट प्रचार है। नमूना उपयोग भी प्रदान किया गया है और परीक्षण किया गया है:

function logStringified (obj) {
    console.log(JSON.stringify(obj));
}

// Create an image with the default attributes.
// Note that a Layout model is created too,
// since we have a default value for "layout".
var img = new Image();
logStringified(img);

// Log the image everytime a "change" is fired.
img.on("change", logStringified);

// Creates the nested model with the given attributes.
img.set("layout", { x: 100, y: 100 });

// Writing on the layout propagates "change" to the image.
// This makes the image also fire a "change", because of `_propagateChange`.
img.get("layout").set("x", 50);

// You may also set model instances yourself.
img.set("layout", new Layout({ x: 100, y: 100 }));

आउटपुट:

{"name":"example","layout":{"x":0,"y":0}}
{"name":"example","layout":{"x":100,"y":100}}
{"name":"example","layout":{"x":50,"y":100}}
{"name":"example","layout":{"x":100,"y":100}}

2

मुझे लगता है कि मुझे इस पार्टी में देर हो गई है, लेकिन हमने हाल ही में इस परिदृश्य से निपटने के लिए एक प्लगइन जारी किया है। इसे बैकबोन-नेस्टिफाई कहा जाता है ।

तो आपका नेस्टेड मॉडल अपरिवर्तित रहता है:

var Layout = Backbone.Model.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

2

रीढ़-रूपों का उपयोग करें

यह नेस्टेड फॉर्म्स, मॉडल्स और टोन्सन को सपोर्ट करता है। सभी नेस्टेड

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

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इस उत्तर की आवश्यकता होगी (उपलब्ध है, यदि आप कल्पना करते हैं, एक मुट्ठी के रूप में )।


1

हमारे पास भी यह समस्या है और एक टीम कार्यकर्ता ने बैकबोन-नेस्टेड-विशेषताओं नामक एक प्लगइन को लागू किया है।

उपयोग बहुत सरल है। उदाहरण:

var Tree = Backbone.Model.extend({
  relations: [
    {
      key: 'fruits',
      relatedModel: function () { return Fruit }
    }
  ]
})

var Fruit = Backbone.Model.extend({
})

इसके साथ, ट्री मॉडल फल तक पहुँच सकता है:

tree.get('fruits')

आप यहाँ और अधिक informations देख सकते हैं:

https://github.com/dtmtec/backbone-nested-attributes

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.