2012-01-26 8 views
7

Zauważyłem, że gdy wiele atrybutów modelu Backbone są ustawione tak jak są wyzwalaneJak ograniczyć zdarzenia zmiany liczby podczas ustawiania wielu atrybutów?

model.set({ 
    att1:val1, 
    att2:val2 
}); 

dwa wydarzenia zmieniają. Błędnie założyłem, że tylko jedno zdarzenie zmiany zostanie uruchomione po ustawieniu wszystkich atrybutów na.

To może nie wydawać się problemem, ale dzieje się tak, gdy funkcja jest przypisana do att1, która również używa wartości att2. Innymi słowy, jeśli zrobisz to, zmienna att2 zostanie ustawiona na starą wartość atrybutu modelu att2.

Pytanie brzmi, jak temu zapobiec w elegancki sposób. Oczywiście jedną opcją jest ustawienie att2 przed ustawieniem att1 lub powiązanie z att2 (zamiast att1), ale wydaje się, że jest to tylko realna opcja w prostych sytuacjach. Ta ostatnia opcja zakłada również, że atrybuty są ustawione w kolejności, w jakiej są wymienione w metodzie zestawu (co moim zdaniem ma miejsce).

Kilka razy spotkałem się z tym problemem, stąd moje pytanie. Problem polega na tym, że zajęło mi trochę czasu, aby uświadomić sobie, co się właściwie dzieje.

W końcowej notatce, tak samo jak możesz przekazać {ciszę: true} jako opcję zestawu metody, byłoby miło mieć opcję {group: true} (lub coś w tym stylu), wskazując, że zmiana zdarzenia powinny być uruchamiane dopiero po ustawieniu wszystkich atrybutów.

Odpowiedz

7

W bardziej złożonych sytuacjach chciałbym wybrać niestandardowe zdarzenia.

zamiast wiązania do zmiany: att1 lub zmiana: att2 Chciałbym wyszukać określone zdarzenie niestandardowe, które zostanie wywołane po ustawieniu wszystkich atrybutów, które chcesz zmienić w modelu.

model.set({ 
    att1:val1, 
    att2:val2 
}); 
model.trigger('contact:updated'); // you can chose your custom event name yourself 

model.bind('contact:updated', func1); 
... 
func1 = function() { 
    var att2 = model.get('att2'); 
} 

Minusem tego pomysłu jest dodanie nowej linii kodu wszędzie tam, gdzie chcemy wywołać zdarzenie. Jeśli tak się stanie, możesz zmienić lub zastąpić model.set(), aby zrobić to za Ciebie, ale już zmieniasz kod szkieletowy, nie wiesz, co o tym myślisz.

EDIT

po patrząc do kodu źródłowego z kręgosłupem, zauważyłem zdarzenie change jest wyzwalany tuż po change:attribute wyzwalaczy. (Świadczy poniższa snippit)

// Fire `change:attribute` events. 
for (var attr in changes) { 
    if (!options.silent) this.trigger('change:' + attr, this, changes[attr], options); 
} 

// Fire the `"change"` event, if the model has been changed. 
if (!alreadyChanging) { 
    if (!options.silent && this._changed) this.change(options); 
    this._changing = false; 
} 

natomiast this.change(options); odnosi się do tego:

change: function(options) { 
    this.trigger('change', this, options); 
    this._previousAttributes = _.clone(this.attributes); 
    this._changed = false; 
}, 

więc jeśli chcesz być wiążące do zdarzenia zamiast konkretnego change:argument imprezy change, można dojść do funkcja wywołania zwrotnego po zmianie obu atrybutów (lub wszystkich).

Jedynym minusem jest to, że zadziała po DOWOLNEJ zmianie, nawet jeśli zmienisz trzeci lub czwarty atrybut. musisz to obliczyć w ...

mały przykład jak to działa na jsfiddle http://jsfiddle.net/saelfaer/qm8xY/

+0

Dzięki za wejście, Sander. Początkowo korzystałem z niestandardowego zdarzenia, ale zastanawiałem się, czy istnieje opcja "grupowania" zmian zdarzeń, gdy wiele atrybutów jest ustawionych jednocześnie. Na podstawie Twojej odpowiedzi zakładam, że odpowiedź brzmi "nie". Na marginesie, zdarzenia niestandardowe są rzeczywiście potężną opcją. –

+2

Dodałem opcję użycia zdarzenia zmiany globalnej, po wykryciu wyzwalaczy po wywołaniu atrybutu logów – Sander

+0

Wielkie dzięki, Sander. To całkowicie wyjaśnia problem. –

Powiązane problemy