"Backbone.js - Backbone.sync या jQuery.ajax में संपूर्ण संग्रह को कैसे सहेजा जाए?"


81

मैं अच्छी तरह से जानता हूं कि यह किया जा सकता है और मैंने काफी जगहों पर देखा है (सहित: एक पूरे संग्रह को बचाने के लिए सर्वश्रेष्ठ अभ्यास? )। लेकिन मैं अभी भी स्पष्ट नहीं हूँ "बिल्कुल कैसे" यह कोड में लिखा है? (पोस्ट इसे अंग्रेजी में समझाता है। जावास्क्रिप्ट विशिष्ट विवरण के लिए बहुत अच्छा होगा :)

मान लीजिए कि मेरे पास मॉडलों का एक संग्रह है - मॉडल स्वयं के पास नेस्टेड संग्रह हो सकते हैं। मैंने मूल संग्रह की toJSON () विधि को ओवरराइड कर दिया है और मुझे एक वैध JSON ऑब्जेक्ट मिल रहा है। मैं संपूर्ण संग्रह (इसी JSON) को "सेव" करना चाहता हूं, लेकिन बैकबोन उस कार्यक्षमता के साथ नहीं आता है।

var MyCollection = Backbone.Collection.extend({
model:MyModel,

//something to save?
save: function() {
   //what to write here?
 }

});

मुझे पता है कि आपको कुछ कहना है:

Backbone.sync = function(method, model, options){
/*
 * What goes in here?? If at all anything needs to be done?
 * Where to declare this in the program? And how is it called?
 */
}

एक बार 'दृश्य' प्रसंस्करण के साथ किया जाता है, यह सर्वर पर खुद को "बचाने" के लिए संग्रह को बताने के लिए ज़िम्मेदार है (एक बल्क अपडेट / हैंडलिंग अनुरोध को संभालने में सक्षम)।

उठने वाले प्रश्न:

  1. "यह सब एक साथ तार करें" कोड में कैसे / क्या लिखना है?
  2. कॉलबैक का 'सही' स्थान क्या है और "सफलता / त्रुटि" कॉलबैक कैसे निर्दिष्ट करें? मेरा मतलब सिंटैक्टली है! मैं बैकबोन में कॉलबैक रजिस्टर करने के सिंटैक्स के बारे में स्पष्ट नहीं हूं ...

अगर यह वास्तव में एक मुश्किल काम है, तो क्या हम jQuery.ajax को एक दृश्य में कॉल कर सकते हैं और सफलता this.successMethodया this.errorMethodत्रुटि कॉलबैक पास कर सकते हैं ?? क्या ये काम करेगा?

मुझे रीढ़ की हड्डी के सोचने के तरीके के साथ तालमेल बिठाने की ज़रूरत है - मुझे पता है कि मैं निश्चित रूप से कुछ wrt को याद कर रहा हूँ, पूरे संग्रह को सिंक कर रहा हूँ।


क्या आपका सर्वर-साइड कोड इसे एकल अनुरोध के रूप में ले सकता है? दूसरे शब्दों में, संपूर्ण शीर्ष स्तर संग्रह, सभी मॉडल, और एकल JSON पैकेट के रूप में नेस्टेड संग्रह? या, क्या आपको प्रत्येक मॉडल को व्यक्तिगत रूप से सहेजने की आवश्यकता है? संपादित करें: आह, करीब पढ़ें, सर्वर "बल्क अपडेट / क्रिएट" करने में सक्षम है
एडवर्ड एम स्मिथ

@ एडवर्ड: हाँ! इसे स्पष्ट कर दिया था क्योंकि यह आमतौर पर चिंता का विषय है, लेकिन इस मामले में नहीं :)
पीएचडी

तो, सर्वर को प्राप्त होने वाले डेटा की संरचना क्या है?
एडवर्ड एम स्मिथ

@ एडवर्ड: क्या डेटा की संरचना मायने रखती है? एक टिप्पणी में प्रारूपण संभव नहीं है, लेकिन यह इस तरह है: [{पोस्टआईड: 1, लेबल: [{आईडी: 1, नाम: "एक"}, {आईडी: 2, नाम: "बी"}}]] मूल रूप से प्रत्येक " postId "में लेबल का एक सेट / सरणी हो सकता है जो स्वयं ऑब्जेक्ट हैं। ऐसे कई पोस्ट हो सकते हैं ... मुझे नहीं लगता कि डेटा प्रारूप को हाथ में मुद्दे के साथ कुछ भी करने के लिए मिला है, जब तक कि मैं कुछ याद नहीं कर रहा हूं
पीएचडी

जवाबों:


64

मेरा तत्काल विचार Backbone.Collection पर सहेजें पद्धति पर विधि को ओवरराइड करने के लिए नहीं है, लेकिन संग्रह को किसी अन्य Backbone.Model में लपेटें और उस पर toJSON विधि को ओवरराइड करें। फिर Backbone.js मॉडल को एक ही संसाधन के रूप में मानेंगे और आपको उस तरीके को हैक करने की ज़रूरत नहीं है जो बहुत अधिक सोचता है।

ध्यान दें कि Backbone.Collection में एक toJSON विधि है, इसलिए आपका अधिकांश कार्य आपके लिए किया जाता है। आपको बस अपने आवरण बैकबोन की toJSON विधि को प्रॉक्सी करना है। Backbone.collection को मेल करें।

var MyCollectionWrapper = Backbone.Model.extend({
url: "/bulkupload",

//something to save?
toJSON: function() {
    return this.model.toJSON(); // where model is the collection class YOU defined above
 }

});

3
मैंने स्रोत कोड के माध्यम से देखा और ऐसा लगता है कि संग्रह में एक बचत विधि नहीं है, इसलिए ओवरराइडिंग में कोई समस्या नहीं होनी चाहिए (यदि यह एक बचत विधि है तो दुनिया बहुत आसान होगी :)
PhD

आवरण विचार के लिए +1 - स्वच्छ और मीठा। यह बिल्कुल नहीं सोचा था। मैं सोच रहा था कि शायद मुझे सीधे Backboard.sync कॉल करना होगा और "मॉडल" तर्क के स्थान पर संग्रह को पास करना होगा। हालांकि यह काम करने के लिए मॉडल के लिए एक यूआरएल निर्दिष्ट करने की आवश्यकता होगी ... किसी भी विचार? चूंकि सिंक विधि आंतरिक रूप से केवल getURL(model)मॉडल तर्क पर कॉल करती है और किसी भी प्रकार की तुलना नहीं करती है ... या तो डिजाइन द्वारा जानबूझकर किया गया लगता है
PhD

3
सहमत - बहुत सुंदर। हालांकि, मैं इस समाधान के साथ एक समस्या में चल रहा हूं: मेरा आवरण मॉडल हमेशा नया होता है, इस प्रकार जब मैं बचाता हूं () तो यह हमेशा एक POST होता है। मैंने अपना डेटा पहले ही प्राप्त कर लिया है, इसलिए जब मैं सहेजता हूं (तो) यह एक PUT होना चाहिए। मुझे लगता है कि मैं कठिन कोड कर सकता हूं। नया () = गलत है, या नकली आईडी सेट करता है, लेकिन यह एक सुंदर समाधान नहीं लगता है। क्या तुम्हारे पास कोई सुझाव है?
स्कॉट स्विट्जर

1
वास्तव में साफ जवाब, यह देखना अच्छा होगा कि आप कैसे कलेक्शन करें।
एंथनी

हां, इसने मेरे और +1 के लिए भी अच्छे प्रयास किए लेकिन अगर मैं सर्वर को दो संग्रह भेजना चाहता हूं, तो मैं कैसे जाऊं?
कोडनॉटफाउंड

25

एक बहुत ही सरल ...

Backbone.Collection.prototype.save = function (options) {
    Backbone.sync("create", this, options);
};

... आपके संग्रह को एक बचत विधि देगा। यह ध्यान रखें कि जो भी परिवर्तित हुआ है, वह सभी संग्रह के मॉडल को सर्वर पर पोस्ट करेगा। विकल्प सिर्फ सामान्य jQuery के अजाक्स विकल्प हैं।


4
सही लगता है। हो सकता है जोड़ना return Backbone.sync..अधिक Backbonish हो।
यवेस एम्सलेम

मुझे लगता है - टाइप के लिए - अपडेट बनाने से बेहतर होगा ... Btw। आप मॉडल या संग्रह के toJSON को ओवरराइड कर सकते हैं, इसलिए आप सर्वर को भेजने के लिए क्या विनियमित कर सकते हैं ... (आमतौर पर सिर्फ आईडी विशेषता की आवश्यकता है) Backbone.Relational में आप यह भी सेट कर सकते हैं कि json प्रारूप में क्या जोड़ा जाए।
inf3rno

1
Backbone.sync "create" की उम्मीद कर रहा है, backbonejs.org/docs/backbone.html#section-141
hacklikecrack

8

मैं इस पद्धति की तरह 'सेव' करने के लिए समाप्त हो गया और $ .ajax को इसके भीतर बुलाया। इसने मुझे अपना एक और अधिक नियंत्रण प्रदान किया, जिसमें एक रैपर वर्ग को जोड़ने की आवश्यकता नहीं थी क्योंकि @brandgonesurfing ने सुझाव दिया था (हालाँकि मुझे यह विचार बहुत पसंद है :) जैसा कि मेरे पास पहले से ही संग्रह था ।toJSON () विधि को ओवरराइड करने की सभी विधि जो मैं कर रहा था, उसका उपयोग कर रहा था। अजाक्स कॉल में ...

आशा है कि यह मदद करता है जो उस पर ठोकर ...


3
आप Backbone.ajax को कॉल करना बेहतर होगा (यह वैसे भी jQuery के लिए प्रॉक्सी करता है, लेकिन यह इसे और अधिक बनाए रखता है)
developerbmw

5

यह वास्तव में ग्राहक और सर्वर के बीच अनुबंध पर निर्भर करता है। यहां एक सरलीकृत कॉफीस्क्रिप्ट उदाहरण दिया गया है, जहां PUT के /parent/:parent_id/childrenसाथ {"children":[{child1},{child2}]}एक माता-पिता के बच्चों को PUT में बदल दिया जाएगा और वापस आ जाएगा {"children":[{child1},{child2}]}:

class ChildElementCollection extends Backbone.Collection
  model: Backbone.Model
  initialize: ->
    @bind 'add', (model) -> model.set('parent_id', @parent.id)

  url: -> "#{@parent.url()}/children" # let's say that @parent.url() == '/parent/1'
  save: ->
    response = Backbone.sync('update', @, url: @url(), contentType: 'application/json', data: JSON.stringify(children: @toJSON()))
    response.done (models) => @reset models.children
    return response

यह एक बहुत ही सरल उदाहरण है, आप और भी बहुत कुछ कर सकते हैं ... यह वास्तव में इस बात पर निर्भर करता है कि आपके डेटा को सेव () में किस स्थिति में निष्पादित किया जाता है, इसे सर्वर पर शिप करने के लिए किस स्थिति में होना चाहिए और सर्वर क्या देता है वापस।

यदि आपका सर्वर PUT के साथ ठीक है [{child1},{child2], तो आपकी Backbone.sync लाइन बदल सकती है response = Backbone.sync('update', @toJSON(), url: @url(), contentType: 'application/json')


विकल्पों का गुण "url" यहाँ neccessary नहीं है))
सर्गेई Kamardin

5

उत्तर इस बात पर निर्भर करता है कि आप सर्वर साइड पर संग्रह के साथ क्या करना चाहते हैं।

यदि आपको पोस्ट के साथ अतिरिक्त डेटा भेजना है तो आपको एक रैपर मॉडल या एक रिलेशनल मॉडल की आवश्यकता हो सकती है ।

साथ आवरण मॉडल आप हमेशा अपनी खुद की लिखने की पार्स विधि:

var Occupants = Backbone.Collection.extend({
    model: Person
});

var House = Backbone.Model.extend({
    url: function (){
        return "/house/"+this.id;
    },
    parse: function(response){
        response.occupants = new Occupants(response.occupants)
        return response;
    }
});

संबंधपरक मॉडल बेहतर हैं, मुझे लगता है, क्योंकि आप उन्हें आसानी से कॉन्फ़िगर कर सकते हैंऔर आप शामिल कर सकते हैं शामिल करें InJSON विकल्प जो आपके बाकी सेवा को भेजने वाले json में डालने के लिए विशेषता है।

var House = Backbone.RelationalModel.extend({
    url: function (){
        return "/house/"+this.id;
    },
    relations: [
        {
            type: Backbone.HasMany,
            key: 'occupants',
            relatedModel: Person,
            includeInJSON: ["id"],
            reverseRelation: {
                key: 'livesIn'
            }
        }
    ]
});

यदि आप अतिरिक्त डेटा नहीं भेजते हैं , तो आप संग्रह को ही सिंक कर सकते हैं । आपको उस स्थिति में अपने संग्रह (या संग्रह प्रोटोटाइप) में एक बचत विधि जोड़ना होगा :

var Occupants = Backbone.Collection.extend({
    url: "/concrete-house/occupants",
    model: Person,
    save: function (options) {
        this.sync("update", this, options);
    }
});

3

मुझे यह भी आश्चर्य हुआ कि बैकबोन संग्रह में एक बिल्ट इन सेव नहीं है। यहाँ मैं यह करने के लिए अपने रीढ़ की हड्डी संग्रह पर डाल दिया है। मैं निश्चित रूप से संग्रह में प्रत्येक मॉडल के माध्यम से पुनरावृति नहीं करना चाहता हूं और स्वतंत्र रूप से सहेजता हूं। इसके अलावा, मैं बैकबोन का उपयोग कर रहा हूं नोड पर बैकऑन का उपयोग कर रहा हूं, इसलिए मैं Backbone.syncअपने छोटे प्रोजेक्ट पर एक फ्लैट फ़ाइल को सहेजने के लिए देशी को ओवरराइड कर रहा हूं - लेकिन कोड बहुत अधिक होना चाहिए:

    save: function(){                                                                                                                                                                                                                                                                                                                                                     
      Backbone.sync('save', this, {                                                                                                                                                                                                                                                                                                                                     
        success: function(){                                                                                                                                                                                                                                                                                                                                          
          console.log('users saved!');                                                                                                                                                                                                                                                                                                                              
        }                                                                                                                                                                                                                                                                                                                                                             
      });                                                                                                                                                                                                                                                                                                                                                               
    }

समझ में भी सिर्फ विकल्प पारित करने के लिए, जैसेsave: function (options) { Backbone.sync('save', this, options); }
मैट फ्लेचर

3

पुराना सूत्र मुझे पता है, जो मैंने किया, वह निम्नलिखित है:

Backbone.Collection.prototype.save = function (options) {
            // create a tmp collection, with the changed models, and the url
            var tmpCollection = new Backbone.Collection( this.changed() );
            tmpCollection.url = this.url;
            // sync
            Backbone.sync("create", tmpCollection, options);
        };
        Backbone.Collection.prototype.changed = function (options) {
            // return only the changed models.
            return this.models.filter( function(m){
                return m.hasChanged()
            });
        };
// and sync the diffs.
self.userCollection.save();

बहुत तनावपूर्ण foreward :)


2

यहाँ एक सरल उदाहरण है:

var Books = Backbone.Collection.extend({
model: Book,
url: function() {
  return '/books/';
},
save: function(){
  Backbone.sync('create', this, {
    success: function() {
      console.log('Saved!');
    }
  });
 }
});

जब आप अपने संग्रह पर सहेजें () विधि को कॉल करते हैं, तो यह परिभाषित URL पर एक PUT विधि अनुरोध भेजेगा।


मैं सोच रहा था कि क्या आप मेरे संग्रह को सहेजने के मुद्दे को हल करने में मदद कर सकते हैं, अभी jsfiddle.net/kyllle/f1h4cz7f/3 toJSON () प्रत्येक मॉडल को अपडेट करता है लेकिन फिर कोई डेटा नहीं लगता है?
स्टाइलर

1

मैं कुछ इस तरह की कोशिश करेंगे:

var CollectionSync = function(method, model, [options]) {
    // do similar things to Backbone.sync
}

var MyCollection = Backbone.Collection.extend({
    sync: CollectionSync,
    model: MyModel,
    getChanged: function() {
        // return a list of models that have changed by checking hasChanged()
    },
    save: function(attributes, options) {
        // do similar things as Model.save
    }
});

( https://stackoverflow.com/a/11085198/137067 )


1

स्वीकृत उत्तर बहुत अच्छा है, लेकिन मैं एक कदम आगे जा सकता हूं और आपको वह कोड दे सकता हूं जिससे यह सुनिश्चित हो सके कि आपके श्रोताओं के लिए उचित घटनाओं को निकाल दिया जाए, साथ ही आपको विकल्प ajax ईवेंट कॉलबैक में पास करने की अनुमति दी जाए:

save: function( options ) {
  var self = this;

  var success = options.success;
  var error = options.error;
  var complete = options.complete;

  options.success = function( response, status, xhr ) {
    self.trigger('sync', self, response, options);
    if (success) return success.apply(this, arguments);
  };

  options.error = function( response, status, xhr ) {
    self.trigger('error', self, response, options);
    if (error) return error.apply(this, arguments);
  };

  options.complete = function( response, status, xhr ) {
    if (complete) return complete.apply(this, arguments);
  }

  Backbone.sync('create', this, options);
}

0

2017 में जो कोई भी बैकबोन.जेएस का उपयोग कर रहा है, उसके लिए स्वीकृत उत्तर काम नहीं कर रहा है।

रैपर मॉडल में ओवरजॉन () ओवरराइड को हटाने की कोशिश करें और जब आप मॉडल के आवरण को तुरंत हटाते हैं, तो कलेक्शन पर कॉल करें।

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