Knockout.js и отключение метки привязки
Как отключить и активировать тег привязки с этой настраиваемой привязкой. Он отлично работает с элементами ввода, но тег привязки просто изменяет CSS, а не отключает.
<a href="link" data-bind="myDisabled: !enabled()"/>
ko.bindingHandlers.myDisabled = {
update: function(element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
ko.bindingHandlers.css.update(element, function() {return { disabled: value }; });
ko.bindingHandlers.disable.update(element, valueAccessor);
}
};
Ответы
Ответ 1
Вам нужно зафиксировать событие click в обработчике привязки.
HTML
<a href="link" data-bind="disableClick: !enabled()">test</a>
<br/><br/><br/>
<input type="checkbox" data-bind="checked: enabled"> enabled
JavaScript
ko.bindingHandlers.disableClick = {
init: function (element, valueAccessor) {
$(element).click(function(evt) {
if(valueAccessor())
evt.preventDefault();
});
},
update: function(element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
ko.bindingHandlers.css.update(element, function() {return { disabled_anchor: value }; });
}
};
ko.applyBindings({ enabled: ko.observable(false)});
Вот рабочий пример:
http://jsfiddle.net/kp74u/54/
ОБНОВЛЕНИЕ 1. Если вам нужно предотвратить привязку других обработчиков событий после привязки обработчика нокаута, вам нужно добавить stopImmediatePropagation
в обработчик событий вместе с preventDefault
.
example: http://jsfiddle.net/kp74u/55/
ОБНОВЛЕНИЕ 2. Если вы хотите отключить все обработчики событий (вместе с обработчиками событий щелчка, прикрепленными до вашего обработчика привязки, вам нужно "взломать" массив событий jquery). Обратите внимание, что это может не работать с другими версиями jquery (пример использует 1.7):
ko.bindingHandlers.disableClick = {
init: function(element, valueAccessor) {
$(element).click(function(evt) {
alert('test before');
});
$(element).click(function(evt) {
if (valueAccessor()) {
evt.preventDefault();
evt.stopImmediatePropagation();
}
});
//begin of 'hack' to move our 'disable' event handler to top of the stack
var events = $.data(element, "events");
console.log(events);
var handlers = events['click'];
if (handlers.length == 1) {
return;
}
handlers.splice(0, 0, handlers.pop());
//end of 'hack' to move our 'disable' event handler to top of the stack
$(element).click(function(evt) {
alert('test after');
});
},
update: function(element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
ko.bindingHandlers.css.update(element, function() {
return {
disabled_anchor: value
};
});
}
};
example: http://jsfiddle.net/nickolsky/kp74u/40/
ОБНОВЛЕНИЕ 3. Как уже упоминалось (предлагаемое редактирование FIR55TORM, извините, не могу утвердить это полностью правильное редактирование, потому что я тоже поздно, чтобы просмотреть): если вы используете jQuery 1.10.x, вам нужно будет добавить знак подчеркивания для доступа к объекту "data" следующим образом:
var events = $._data(element, "events");
Пересмотренная скрипка для jQuery 1.10.x: http://jsfiddle.net/nickolsky/kp74u/41/
Ответ 2
Я нашел этот ответ, когда посмотрел на способ сделать это, но мне не понравился этот подход, так же как и мой собственный
var orgClickInit = ko.bindingHandlers.click.init;
ko.bindingHandlers.click.init = function (element, valueAccessor, allBindingsAccessor, viewModel) {
if (element.tagName === "A" && allBindingsAccessor().enable != null) {
var disabled = ko.computed(function () {
return ko.utils.unwrapObservable(allBindingsAccessor().enable) === false;
});
ko.applyBindingsToNode(element, { css: { disabled: disabled} });
var handler = valueAccessor();
valueAccessor = function () {
return function () {
if (ko.utils.unwrapObservable(allBindingsAccessor().enable)) {
handler.apply(this, arguments);
}
}
};
}
orgClickInit(element, valueAccessor, allBindingsAccessor, viewModel);
};
Его бесшовные с естественным щелчком и включением привязки (отключить привязку не реализовано)
Fiddle (Fiddle также использует мою библиотеку с конфигурацией для конференции)
http://jsfiddle.net/xCfQC/30/
Ответ 3
Использование @Anders в качестве вдохновения, я придумал свою собственную версию этого. Позволяет использовать "enable", "disable" с или без "click". Также допускается настраиваемый отключенный класс, в противном случае по умолчанию используется значение "отключено".
var koEnableUpdateOrig = ko.bindingHandlers.enable.update;
ko.bindingHandlers.enable.update = function (element, valueAccessor, allBindings) {
// call original enable update
var result = koEnableUpdateOrig.apply(this, arguments);
var enabled = ko.unwrap(valueAccessor());
// get and apply disabled class
var disabledClass = "disabled";
if (allBindings)
disabledClass = allBindings().disabledClass || "disabled";
if (enabled) {
$(element).removeClass(disabledClass);
if (element.tagName === "A")
$(element).off("click.koEnableUpdate");
}
else {
$(element).addClass(disabledClass);
if (element.tagName === "A")
$(element).on("click.koEnableUpdate", function (e) { e.preventDefault(); });
}
return result;
};
ko.bindingHandlers.disable.update = function (element, valueAccessor, allBindings) {
// call enable with the reverse value
// the original knockout disable does this, but does not pass the allBindings
ko.bindingHandlers.enable.update(element, function () {
return !ko.unwrap(valueAccessor())
}, allBindings);
};
var koClickInitOrig = ko.bindingHandlers.click.init;
ko.bindingHandlers.click.init = function (element, valueAccessor, allBindings) {
// wrap click function with enable/disable check
var valueAccessorOrig = valueAccessor();
valueAccessor = function () {
return function () {
if (ko.unwrap(allBindings().enable) ||
(allBindings().disable == null || !ko.unwrap(allBindings().disable))) {
valueAccessorOrig.apply(this, arguments);
}
}
};
// apply wrapped click to original click init
koClickInitOrig.apply(this, arguments);
};
Ответ 4
Это мой подход:
JavaScript
(function () {
var originalDisableUpdate = ko.bindingHandlers.disable.update;
ko.bindingHandlers.disable.update = function (element, valueAccessor) {
if (element.tagName === 'A') {
var
value = ko.utils.unwrapObservable(valueAccessor()),
disabled = 'disabled';
if (value) {
element.setAttribute(disabled, null);
}
else {
element.removeAttribute(disabled);
}
}
else {
originalDisableUpdate(element, valueAccessor);
}
};
})();
CSS
a[disabled] {
pointer-events:none;
cursor:default;
}