Zdaję sobie sprawę, że można to zrobić i przyjrzałem się kilku miejscom (w tym: Najlepsza praktyka zapisywania całej kolekcji? ). Ale nadal nie wiem, „dokładnie jak” jest napisane w kodzie? (post wyjaśnia to po angielsku. Byłoby wspaniale mieć wyjaśnienie specyficzne dla javascript :)
Powiedzmy, że mam kolekcję modeli - same modele mogą mieć kolekcje zagnieżdżone. Zastąpiłem metodę toJSON () kolekcji nadrzędnej i otrzymuję prawidłowy obiekt JSON. Chcę „zapisać” całą kolekcję (odpowiadający jej kod JSON), ale szkielet nie wydaje się mieć wbudowanej takiej funkcjonalności.
var MyCollection = Backbone.Collection.extend({
model:MyModel,
//something to save?
save: function() {
//what to write here?
}
});
Wiem gdzieś musisz powiedzieć:
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?
*/
}
Gdy „przeglądanie” zakończy się wraz z przetwarzaniem, jest ono odpowiedzialne za polecenie kolekcji, aby „zapisała się” na serwerze (zdolnym do obsługi zbiorczego żądania aktualizacji / tworzenia).
Pytania, które się pojawiają:
- Jak / co napisać w kodzie, aby „połączyć to wszystko razem”?
- Jaka jest „właściwa” lokalizacja wywołań zwrotnych i jak określić wywołanie zwrotne „powodzenie / błąd”? Mam na myśli składnię? Nie jestem pewien składni rejestracji callbacków w sieci szkieletowej ...
Jeśli jest to rzeczywiście trudne zadanie, czy możemy wywołać jQuery.ajax w widoku i przekazać this.successMethod
lub this.errorMethod
jako wywołanie zwrotne sukcesu / błędu? Czy to zadziała?
Muszę się zsynchronizować ze sposobem myślenia kręgosłupa - wiem, że na pewno brakuje mi czegoś podczas synchronizacji całych kolekcji.
źródło
Odpowiedzi:
Moją natychmiastową myślą nie jest przesłonięcie metody przy zapisywaniu metody w Backbone.Collection, ale zawinięcie kolekcji w inny Backbone.Model i zastąpienie metody toJSON. Wtedy Backbone.js potraktuje model jako pojedynczy zasób i nie musisz hakować sposobu, w jaki backone myśli za dużo.
Zauważ, że Backbone.Collection ma metodę toJSON, więc większość pracy jest wykonywana za Ciebie. Wystarczy, że przekierujesz metodę toJSON swojego opakowania Backbone.Model do kolekcji 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 } });
źródło
getURL(model)
argument modelu i nie wykonuje też żadnego rodzaju porównań ... wydaje się być zamierzona z założeniaBardzo prosta ...
Backbone.Collection.prototype.save = function (options) { Backbone.sync("create", this, options); };
... zapewni Twoim kolekcjom metodę zapisu. Pamiętaj, że to zawsze spowoduje wysłanie wszystkich modeli kolekcji na serwer, niezależnie od tego, co się zmieniło. opcje są zwykłymi opcjami jQuery ajax.
źródło
return Backbone.sync..
jest bardziej Backbonish.Skończyło się na metodzie podobnej do 'save' i wywołaniu w niej $ .ajax. Dało mi to większą kontrolę nad tym bez potrzeby dodawania klasy opakowującej, jak sugerował @brandgonesurfing (chociaż bardzo mi się podoba ten pomysł :) Jak wspomniałem, ponieważ już miałem metodę collection.toJSON () nadpisała wszystko, co zrobiłem, to jej używanie w wywołaniu Ajax ...
Mam nadzieję, że pomoże to komuś, kto się na to natknie ...
źródło
To naprawdę zależy od tego, jaka jest umowa między klientem a serwerem. Oto uproszczony przykład CoffeeScript, w którym PUT na
/parent/:parent_id/children
z{"children":[{child1},{child2}]}
zamieni dzieci rodzica na to, co jest w PUT i zwróci{"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
To jest dość prosty przykład, możesz zrobić o wiele więcej ... to naprawdę zależy od stanu twoich danych podczas wykonywania funkcji save (), w jakim stanie muszą być, aby zostały wysłane na serwer i co daje serwer plecy.
Jeśli twój serwer jest w porządku z PUT wynoszącym
[{child1},{child2]
, to linia Backbone.sync może zmienić się naresponse = Backbone.sync('update', @toJSON(), url: @url(), contentType: 'application/json')
.źródło
Odpowiedź zależy od tego, co chcesz zrobić z kolekcją po stronie serwera.
Jeśli musisz wysłać dodatkowe dane z postem, możesz potrzebować modelu opakowującego lub modelu relacyjnego .
W przypadku modelu opakowania zawsze musisz napisać własną metodę parsowania :
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; } });
Wydaje mi się, że modele relacyjne są lepsze, ponieważ można je łatwiej konfigurować i regulować za pomocąopcji includeInJSON , które atrybuty należy umieścić w pliku json wysyłanym do usługi odpoczynku.
var House = Backbone.RelationalModel.extend({ url: function (){ return "/house/"+this.id; }, relations: [ { type: Backbone.HasMany, key: 'occupants', relatedModel: Person, includeInJSON: ["id"], reverseRelation: { key: 'livesIn' } } ] });
Jeśli nie wyślesz dodatkowych danych , możesz zsynchronizować samą kolekcję . W takim przypadku musisz dodać metodę save do swojej kolekcji (lub prototypu kolekcji):
var Occupants = Backbone.Collection.extend({ url: "/concrete-house/occupants", model: Person, save: function (options) { this.sync("update", this, options); } });
źródło
Zaskoczyło mnie również, że kolekcje Backbone nie mają wbudowanego zapisu. Oto, co umieściłem w mojej kolekcji kręgosłupa, aby to zrobić. Zdecydowanie nie chcę iterować każdego modelu w kolekcji i niezależnie zapisywać. Ponadto używam Backbone na zapleczu przy użyciu Node, więc zastępuję natywny,
Backbone.sync
aby zapisać do pliku płaskiego w moim małym projekcie - ale kod powinien być prawie taki sam:save: function(){ Backbone.sync('save', this, { success: function(){ console.log('users saved!'); } }); }
źródło
save: function (options) { Backbone.sync('save', this, options); }
Stary wątek, który znam, skończyło się na tym:
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();
Dość naprzód :)
źródło
Oto prosty przykład:
var Books = Backbone.Collection.extend({ model: Book, url: function() { return '/books/'; }, save: function(){ Backbone.sync('create', this, { success: function() { console.log('Saved!'); } }); } });
Gdy wywołasz metodę save () w swojej kolekcji, wyśle ona żądanie metody PUT do zdefiniowanego adresu URL.
źródło
Spróbowałbym czegoś takiego:
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 )
źródło
Zaakceptowana odpowiedź jest całkiem dobra, ale mogę pójść o krok dalej i podać kod, który zapewni odpalanie odpowiednich zdarzeń dla twoich słuchaczy, jednocześnie umożliwiając przekazanie opcji wywołań zwrotnych zdarzeń 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); }
źródło
Dla każdego, kto nadal korzysta z backbone.js w 2017 roku, zaakceptowana odpowiedź nie działa.
Spróbuj usunąć przesłonięcie toJSON () w modelu opakowania i wywołać toJSON w kolekcji podczas tworzenia wystąpienia opakowania modelu.
new ModelWrapper(Collection.toJSON());
źródło