Изменить событие на select с привязкой к нокауту, как я могу узнать, действительно ли это реальное изменение
Я создаю пользовательский интерфейс с разрешениями, у меня есть список разрешений с выбранным списком рядом с каждым разрешением. Разрешения представлены наблюдаемым массивом объектов, привязанных к списку выбора:
<div data-bind="foreach: permissions">
<div class="permission_row">
<span data-bind="text: name"></span>
<select data-bind="value: level, event:{ change: $parent.permissionChanged}">
<option value="0"></option>
<option value="1">R</option>
<option value="2">RW</option>
</select>
</div>
</div>
Теперь проблема заключается в следующем: событие изменения возникает, когда пользовательский интерфейс только что заполняется в первый раз. Я вызываю свою функцию ajax, получаю список разрешений, а затем событие увеличивается для каждого элемента разрешения. Это действительно не то поведение, которое я хочу. Я хочу, чтобы он был поднят только тогда, когда пользователь действительно выбирает новое значение для разрешения в списке выбора, как я могу это сделать?
Ответы
Ответ 1
Фактически вы хотите узнать, запускается ли событие пользователем или программой, и очевидно, что событие будет инициироваться при инициализации.
Подход нокаута добавления subscription
не поможет во всех случаях, почему, поскольку в большинстве моделей будет реализовано как
- запустите модель с данными undefined, просто структура
(actual KO initilization)
- обновить модель с исходными данными
(logical init like load JSON , get data etc)
- Пользовательское взаимодействие и обновления
Фактический шаг, который мы хотим захватить, - это изменения в 3, но на втором этапе subscription
получит вызов,
Таким образом, лучший способ - добавить к изменению события, например
<select data-bind="value: level, event:{ change: $parent.permissionChanged}">
и обнаружил событие в permissionChanged
функции
this.permissionChanged = function (obj, event) {
if (event.originalEvent) { //user changed
} else { // program changed
}
}
Ответ 2
Это просто предположение, но я думаю, что это происходит, потому что level
- это число. В этом случае привязка value
вызовет событие change
для обновления level
строковым значением. Поэтому вы можете исправить это, убедившись, что level
- это строка для начала.
Кроме того, чем больше "нокаут" это делает, так это не использовать обработчики событий, а использовать наблюдаемые и подписки. Сделайте level
наблюдаемым, а затем добавьте к нему подписку, которая будет запускаться всякий раз, когда изменяется level
.
Ответ 3
Вот решение, которое может помочь в этом странном поведении. Я не мог найти лучшего решения, чем поместить кнопку, чтобы вручную запустить событие изменения.
РЕДАКТИРОВАТЬ: Может быть, пользовательское связывание, подобное этому, может помочь:
ko.bindingHandlers.changeSelectValue = {
init: function(element,valueAccessor){
$(element).change(function(){
var value = $(element).val();
if($(element).is(":focus")){
//Do whatever you want with the new value
}
});
}
};
И в выбранном атрибуте привязки данных добавьте:
changeSelectValue: yourSelectValue
Ответ 4
Я использую эту настраиваемую привязку (основанную на этой скрипке от RP Niemeyer, см. его ответ на this), который гарантирует, что числовое значение будет правильно преобразовано из строки в число (как предложено решением Майкла Бест):
JavaScript:
ko.bindingHandlers.valueAsNumber = {
init: function (element, valueAccessor, allBindingsAccessor) {
var observable = valueAccessor(),
interceptor = ko.computed({
read: function () {
var val = ko.utils.unwrapObservable(observable);
return (observable() ? observable().toString() : observable());
},
write: function (newValue) {
observable(newValue ? parseInt(newValue, 10) : newValue);
},
owner: this
});
ko.applyBindingsToNode(element, { value: interceptor });
}
};
Пример HTML:
<select data-bind="valueAsNumber: level, event:{ change: $parent.permissionChanged }">
<option value="0"></option>
<option value="1">R</option>
<option value="2">RW</option>
</select>
Ответ 5
Если вы используете наблюдаемое вместо примитивного значения, выбор не будет вызывать события изменения при первоначальной привязке. Вы можете продолжать привязываться к событию изменения, а не подписываться непосредственно на наблюдаемое.
Ответ 6
Быстро и грязно, используя простой флаг:
var bindingsApplied = false;
var ViewModel = function() {
// ...
this.permissionChanged = function() {
// ignore, if flag not set
if (!flag) return;
// ...
};
};
ko.applyBindings(new ViewModel());
bindingsApplied = true; // done with the initial population, set flag to true
Если это не сработает, попробуйте обернуть последнюю строку в setTimeout() - события будут асинхронными, поэтому, возможно, последняя еще не выполнена, когда applyBindings() уже возвращен.
Ответ 7
У меня была аналогичная проблема, и я просто модифицировал обработчик событий, чтобы проверить тип переменной. Тип устанавливается только после того, как пользователь выбирает значение, а не при первой загрузке страницы.
self.permissionChanged = function (l) {
if (typeof l != 'undefined') {
...
}
}
Кажется, это работает для меня.
Ответ 8
использовать этот:
this.permissionChanged = function (obj, event) {
if (event.type != "load") {
}
}
Ответ 9
Если вы работаете с помощью Knockout, используйте ключевую функциональность нокаута для наблюдаемых функций.
Используйте метод ko.computed()
и выполните и вызовите вызов ajax внутри этой функции.