KnockoutJS подписывается на несколько наблюдаемых с одним и тем же действием обратного вызова
У меня есть модельный класс в KnockoutJS, который имеет несколько значений, на которые я хочу подписаться. Каждая подписка будет выполнять одну и ту же задачу:
function CaseAssignmentZipCode(zipCode, userId, isNew) {
var self = this;
self.zipCode = ko.observable(zipCode);
self.userId = ko.observable(userId);
self.isNew = isNew;
self.isUpdated = false;
self.zipCode.subscribe(function () { self.isUpdated = true; });
self.userId.subscribe(function () { self.isUpdated = true; });
}
Есть ли способ объединить эти два вызова для подписки, чтобы я мог использовать одну подписку для "просмотра" обоих значений?
Ответы
Ответ 1
Вы можете использовать для этой цели вычисленный наблюдаемый. Вам просто нужно убедиться, что вы получаете доступ к значению каждого наблюдаемого в функции чтения. Будет что-то вроде:
ko.computed(function() {
self.zipCode();
self.userId();
self.isUpdated = true;
});
Итак, вы получаете зависимости от двух наблюдаемых и устанавливаете свой флаг.
Кроме того, если вы ищете что-то вроде "грязного" флага, вы можете рассмотреть что-то вроде: http://www.knockmeout.net/2011/05/creating-smart-dirty-flag-in-knockoutjs.html. Идея состоит в том, что вы используете вычисленное наблюдаемое, которое вызывает ko.toJS() для объекта, чтобы развернуть все его наблюдаемые.
Ответ 2
Вы не хотите дублировать тело функции обработчика? Извлеките его в переменную.
function CaseAssignmentZipCode(zipCode, userId, isNew) {
var self = this;
self.zipCode = ko.observable(zipCode);
self.userId = ko.observable(userId);
self.isNew = isNew;
self.isUpdated = false;
var handler = function () { self.isUpdated = true; };
self.zipCode.subscribe(handler);
self.userId.subscribe(handler);
}
Ответ 3
Улучшение при реорганизации тела функции в переменную путем поворота списка зависимостей для отслеживания в цикле:
function CaseAssignmentZipCode(zipCode, userId, isNew) {
var self = this;
self.zipCode = ko.observable(zipCode);
self.userId = ko.observable(userId);
self.isNew = isNew;
self.isUpdated = false;
var handler = function () { self.isUpdated = true; };
ko.utils.arrayForEach([self.zipCode, self.userId], function(obs) {
obs.subscribe(handler);
});
}
Ответ 4
Для этой цели вы можете создать какое-то расширение. Простой пример:
function subscribeMany(callback, observables) {
for (var i = 0; i < observables.length; i++) {
observables[i].subscribe(callback);
}
}
Использование:
var name = ko.observable();
var email = ko.observable();
var callback = function(value) {
console.log(value);
};
subscribeMany(callback, [name, email]);
name('test 1')
email('test 2')
Ответ 5
Версия Typescript, предназначенная для выполнения одного и того же обратного вызова для любого Observable в списке Observables.
Это решение работает для типов:
-
KnockoutObservableArray<KnockoutObservable<T>>
-
KnockoutObservable<KnockoutObservable<T>[]>
-
KnockoutObservable<T>[]
Преимущества этого подхода:
- Если Observable будет добавлен в ваш
KnockoutObservableArray
то изменение будет обнаружено, и функция подписки будет добавлена и в этот Observable. -
Одно и то же решение может использоваться для множества различных типов, а типы обрабатываются для вас.
function subscribeMany<T>(
observables: KnockoutObservableArray<KnockoutObservable<T>> | KnockoutObservable<KnockoutObservable<T>[]> | KnockoutObservable<T>[],
callback: (v: T) => void
): KnockoutObservableArray<KnockoutObservable<T>> | KnockoutObservable<KnockoutObservable<T>[]> | KnockoutObservable<T>[] {
function _subscribeMany<T>(
observables: KnockoutObservableArray<KnockoutObservable<T>> | KnockoutObservable<KnockoutObservable<T>[]> | KnockoutObservable<T>[],
callback: (v: T) => void): void {
if (_isObservableArray<T>(observables)) {
_subcribeAndRun(observables, (array) => {
array.forEach((observable) => {
observable.subscribe(callback);
});
});
}
else {
ko.unwrap(observables).forEach((observable) => {
observable.subscribe(callback);
});
}
}
function _isObservableArray<T>(observables: KnockoutObservableArray<KnockoutObservable<T>> | KnockoutObservable<KnockoutObservable<T>[]> | KnockoutObservable<T>[]): observables is KnockoutObservableArray<KnockoutObservable<T>> | KnockoutObservable<KnockoutObservable<T>[]> {
return "subscribe" in observables;
}
function _subcribeAndRun<T>(o: KnockoutObservable<T>, callback: (v: T) => void): KnockoutObservable<T> {
o.subscribe(callback);
callback(o());
return o;
}
_subscribeMany<T>(observables, callback);
return observables;
}