2012-01-26 18 views
7

tôi đã nhận thấy rằng khi nhiều thuộc tính của một mô hình Backbone được thiết lập như vậyLàm cách nào để giới hạn sự kiện thay đổi số khi nhiều thuộc tính được đặt?

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

hai sự kiện thay đổi được kích hoạt. Tôi đã giả định sai rằng chỉ có một sự kiện thay đổi sẽ được kích hoạt sau khi tất cả các thuộc tính đã được đặt.

Điều này có vẻ không phải là vấn đề, nhưng đó là khi hàm bị ràng buộc với att1 cũng sử dụng giá trị của att2. Nói cách khác, khi bạn làm điều này

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

biến att2 sẽ được đặt thành giá trị cũ của thuộc tính att2 của mô hình.

Câu hỏi đặt ra là cách ngăn chặn điều này một cách thanh lịch. Tất nhiên, một lựa chọn là đặt att2 trước khi đặt att1 hoặc để liên kết với att2 (thay vì att1), nhưng có vẻ như đây chỉ là một lựa chọn khả thi trong các tình huống đơn giản. Tùy chọn thứ hai cũng giả định rằng các thuộc tính được thiết lập theo thứ tự mà chúng được liệt kê trong phương thức set (đó là trường hợp tôi nghĩ).

Tôi đã gặp vấn đề này nhiều lần do đó câu hỏi của tôi. Vấn đề là nó đã cho tôi một thời gian để nhận ra những gì đã thực sự xảy ra.

Lưu ý cuối cùng, giống như bạn có thể chuyển {im lặng: true} như là một tùy chọn của phương pháp đã đặt, sẽ thật tuyệt khi có tùy chọn {group: true} (hoặc cái gì đó tương tự) cho biết rằng thay đổi các sự kiện chỉ nên được kích hoạt sau khi tất cả các thuộc tính đã được thiết lập.

Trả lời

7

Trong các tình huống phức tạp hơn, tôi sẽ đi đến các sự kiện tùy chỉnh.

thay vì liên kết với thay đổi: att1 hoặc thay đổi: att2 tôi sẽ tìm kiếm sự kiện tùy chỉnh cụ thể mà bạn kích hoạt sau khi bạn đã đặt tất cả thuộc tính bạn muốn thay đổi trên mô hình.

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

Ngược lại với ý tưởng này là bạn phải thêm một dòng mã mới ở mọi nơi bạn muốn kích hoạt sự kiện. nếu điều này xảy ra rất nhiều bạn có thể muốn thay đổi hoặc ghi đè lên model.set() để làm điều đó cho bạn, nhưng sau đó bạn đã thay đổi mã xương sống, không biết bạn cảm thấy thế nào về điều đó.

EDIT

sau khi nhìn vào mã nguồn của xương sống, tôi nhận thấy sự kiện change được kích hoạt ngay sau khi change:attribute gây nên. (Chứng minh bằng các snippit bên dưới)

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

trong khi this.change(options); đề cập đến điều này:

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

vì vậy nếu bạn sẽ được liên kết với các sự kiện change thay vì sự kiện cụ thể change:argument, bạn sẽ đến một chức năng gọi lại sau khi cả hai (hoặc tất cả) thuộc tính được thay đổi.

nhược điểm duy nhất là, nó sẽ kích hoạt bất kỳ thay đổi nào, ngay cả khi bạn thay đổi thuộc tính thứ ba hoặc thứ tư. bạn cần tính toán trong ...

ví dụ nhỏ về cách hoạt động trên jsfiddle http://jsfiddle.net/saelfaer/qm8xY/

+0

Cảm ơn bạn đã nhập, Sander. Ban đầu tôi đã sử dụng một sự kiện tùy chỉnh, nhưng tôi đã tự hỏi liệu có một tùy chọn để "nhóm" thay đổi các sự kiện khi khi nhiều thuộc tính được đặt cùng một lúc hay không. Dựa trên câu trả lời của bạn, tôi cho rằng câu trả lời là không. Trên một lưu ý phụ, sự kiện tùy chỉnh là một lựa chọn mạnh mẽ thực sự. –

+2

tôi đã thêm tùy chọn sử dụng sự kiện thay đổi toàn cầu, sau khi tìm ra nó kích hoạt sau khi attributechang được kích hoạt – Sander

+0

Cảm ơn rất nhiều, Sander. Điều này làm rõ vấn đề hoàn toàn. –

Các vấn đề liên quan