webentwicklung-frage-antwort-db.com.de

"Wie" Speichern einer gesamten Sammlung in Backbone.js - Backbone.sync oder jQuery.ajax

Ich bin mir bewusst, dass dies möglich ist, und ich habe mir einige Orte angesehen (einschließlich: Best Practice zum Speichern einer gesamten Sammlung? ). Aber mir ist immer noch nicht klar "wie genau" wird es im Code geschrieben? (Der Beitrag erklärt es auf Englisch. Es wäre großartig, eine Javascript-spezifische Erklärung zu haben :)

Angenommen, ich habe eine Sammlung von Modellen - die Modelle selbst haben möglicherweise verschachtelte Sammlungen. Ich habe die toJSON () - Methode der übergeordneten Auflistung überschrieben und erhalte ein gültiges JSON-Objekt. Ich möchte die gesamte Sammlung "speichern" (entsprechend JSON), aber das Backbone scheint nicht mit dieser Funktionalität eingebaut zu sein.

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

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

});

Ich weiß, irgendwo muss man sagen:

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?
 */
}

Sobald die "Ansicht" mit der Verarbeitung abgeschlossen ist, ist sie dafür verantwortlich, dass die Sammlung sich auf dem Server "speichert" (die eine Bulk-Aktualisierungs-/Erstellungsanforderung verarbeiten kann). 

Fragen, die sich stellen:

  1. Wie/was schreibe ich Code, um "alles miteinander zu verbinden"?
  2. Wie lauten die richtigen Positionen für die Rückrufe und wie wird ein Rückruf "Erfolg/Fehler" angegeben? Ich meine syntaktisch: Ich weiß nicht, wie man Callbacks im Backbone registriert ...

Wenn es sich tatsächlich um einen kniffligen Job handelt, können wir jQuery.ajax innerhalb einer Ansicht aufrufen und den this.successMethod oder this.errorMethod als Erfolgs-/Fehlerrückrufe übergeben? Wird es funktionieren?

Ich muss mich mit der Denkweise von Backbone synchronisieren - ich weiß, dass ich definitiv etwas verpasse, was die Synchronisierung der gesamten Sammlungen betrifft.

81
PhD

Mein erster Gedanke ist, die Methode in der save-Methode in Backbone.Collection nicht zu überschreiben, sondern die Auflistung in ein anderes Backbone.Model zu verpacken und die toJSON-Methode darauf zu überschreiben. Dann wird Backbone.js das Modell als eine einzige Ressource behandeln, und Sie müssen nicht den Weg, den Backone denkt, zu sehr hacken.

Beachten Sie, dass Backbone.Collection über eine toJSON-Methode verfügt, sodass der Großteil Ihrer Arbeit für Sie erledigt wird. Sie müssen lediglich die toJSON-Methode Ihres Wrappers Backbone.Model an die Backbone.collection übergeben.

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
 }

});
64
bradgonesurfing

Ein sehr einfaches ...

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

... gibt Ihren Sammlungen eine sichere Methode. Beachten Sie, dass dies immer alle Modelle der Sammlung auf dem Server bereitstellt, unabhängig davon, was sich geändert hat. Optionen sind nur normale jQuery-Ajax-Optionen.

25
hacklikecrack

Am Ende hatte ich nur eine "save" -Methode und rief $ .ajax an. Es gab mir mehr Kontrolle darüber, ohne eine Wrapper-Klasse hinzufügen zu müssen, wie @brandgonesurfing vorschlug (obwohl ich die Idee absolut liebe.) im Ajax-Anruf ...

Hoffe, das hilft jemandem, der darauf stößt ...

8
PhD

Dies hängt wirklich davon ab, wie der Vertrag zwischen dem Client und dem Server ist. Hier ist ein vereinfachtes CoffeeScript-Beispiel, bei dem ein PUT für /parent/:parent_id/children mit {"children":[{child1},{child2}]} die Kinder eines Elternteils durch den Inhalt des PUT ersetzt und {"children":[{child1},{child2}]} zurückgibt:

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

Dies ist ein ziemlich einfaches Beispiel, Sie können noch viel mehr tun ... es hängt wirklich davon ab, in welchem ​​Status sich Ihre Daten befinden, wenn save () ausgeführt wird, in welchem ​​Status sie sich befinden muss, um an den Server zu senden, und was der Server angibt zurück.

Wenn Ihr Server mit einem PUT von [{child1},{child2] in Ordnung ist, kann sich Ihre Backbone.sync-Zeile in response = Backbone.sync('update', @toJSON(), url: @url(), contentType: 'application/json') ändern.

5
carpeliam

Die Antwort hängt davon ab, was Sie mit der Sammlung auf der Serverseite tun möchten.

Wenn Sie zusätzliche Daten mit dem Post senden müssen, benötigen Sie möglicherweise ein wrapper-Modell oder ein relationales Modell.

Mit dem wrapper model müssen Sie immer Ihre eigene parse -Methode schreiben:

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

Relationale Modelle sind besser Ich denke, weil Sie einfacher konfigurieren können und Sie können mit der Option includeInJSON festlegen, welche Attribute Sie in den von Ihnen gesendeten Json einfügen möchten zu Ihrem Rastdienst. 

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

Wenn Sie keine zusätzlichen Daten senden, können Sie die Sammlung selbst synchronisieren. In diesem Fall müssen Sie Ihrer Sammlung (oder dem Prototyp der Sammlung) eine save - Methode hinzufügen:

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

Ein alter Thread, den ich kenne, ist folgendes:

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

Ziemlich abzulehnen :)

3
Rene Weteling

Ich war auch überrascht, dass Backbone-Kollektionen keinen eingebauten Save haben. Hier ist, was ich in meine Backbone-Kollektion stecke, um es zu tun. Ich möchte definitiv nicht jedes Modell in der Sammlung durchlaufen und unabhängig speichern. Außerdem verwende ich Backbone auf dem Backend mit Node. Daher überschreibe ich den nativen Code Backbone.sync, um ihn in einer flachen Datei in meinem kleinen Projekt zu speichern. Der Code sollte jedoch ziemlich identisch sein:

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

Hier ist ein einfaches Beispiel:

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

Wenn Sie die save () -Methode Ihrer Sammlung aufrufen, wird eine PUT-Methodenanforderung an die definierte URL gesendet.

2
Gaurav Gupta

Ich würde so etwas versuchen:

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
philfreo

Die akzeptierte Antwort ist ziemlich gut, aber ich kann noch einen Schritt weiter gehen und Ihnen Code geben, der sicherstellt, dass die richtigen Ereignisse für Ihre Zuhörer ausgelöst werden, und Sie können auch Option ajax-Ereignisrückrufe übergeben:

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);
}
1
Throttlehead

Für alle, die noch 2017 backbone.js verwenden, funktioniert die akzeptierte Antwort nicht.

Entfernen Sie die toJSON () - Überschreibung im Wrapper-Modell und rufen Sie toJSON für die Auflistung auf, wenn Sie den Modell-Wrapper instanziieren.

new ModelWrapper(Collection.toJSON());
0
zeros-and-ones