简体   繁体   English

knockout.js和禁用锚标签

[英]knockout.js and disabling anchor tag

How can I disable and enable an anchor tag with this custom binding. 如何使用此自定义绑定禁用和启用锚标记。 It works great with input elements but the anchor tag just changes the CSS, not the disabling. 它适用于输入元素,但是锚标记只是改变了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);
    }
};

You need to capture click event in your binding handler. 您需要在绑定处理程序中捕获click事件。

HTML : HTML

<a href="link" data-bind="disableClick: !enabled()">test</a>
<br/><br/><br/>
<input type="checkbox" data-bind="checked: enabled"> enabled ​

JavaScript : 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)});

Here is a working example: 这是一个工作示例:

http://jsfiddle.net/kp74u/54/ http://jsfiddle.net/kp74u/54/

UPDATE 1 : If you need to prevent other event handlers bound after knockout binding handler was attached, you need to add stopImmediatePropagation to the event handler along with preventDefault . 更新1 :如果您需要阻止在附加敲除绑定处理程序后绑定的其他事件处理程序,则需要将stopImmediatePropagationpreventDefault一起添加到事件处理程序中。

example: http://jsfiddle.net/kp74u/55/ 示例: http//jsfiddle.net/kp74u/55/

UPDATE 2 : If you want to disable all event handlers (along with click event handlers attached before your binding handler, you need to 'hack' the jquery events array). 更新2 :如果要禁用所有事件处理程序(以及在绑定处理程序之前附加的单击事件处理程序,则需要'破解'jquery事件数组)。 Please note that this may not work other versions of jquery (example uses 1.7): 请注意,这可能不适用于其他版本的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/ 例如: http//jsfiddle.net/nickolsky/kp74u/40/

UPDATE 3 : As was mentioned there ( suggested edit by FIR55TORM , sorry can't approve this completely correct edit because I am too late to review): if you're using jQuery 1.10.x, you will need to add an underscore to access the 'data' object like so: 更新3 :正如那里提到的( 建议由FIR55TORM编辑 ,抱歉不能批准这个完全正确的编辑因为我来不及回顾):如果你使用jQuery 1.10.x,你需要添加一个下划线来访问'data'对象如下:

var events = $._data(element, "events"); 

Revised fiddle for jQuery 1.10.x: http://jsfiddle.net/nickolsky/kp74u/41/ 修改jQuery 1.10.x的小提琴: http//jsfiddle.net/nickolsky/kp74u/41/

I found this answer when goggling for a way of doing this, but I didn't like the approach so did my own 我在寻找一种方法时找到了这个答案,但我不喜欢这种方法,所以我自己也做了

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

Its seamless with the native click and enable binding (disable binding not implemented) Fiddle (Fiddle also uses my Convention over configuration library) http://jsfiddle.net/xCfQC/30/ 它与本机点击无关并启用绑定(禁用绑定未实现)Fiddle(Fiddle也使用我的约定配置库) http://jsfiddle.net/xCfQC/30/

Using @Anders answer as inspiration, I came up with my own version of this. 使用@Anders答案作为灵感,我想出了我自己的版本。 Allows for use of "enable", "disable" with or without the "click". 允许在有或没有“点击”的情况下使用“启用”,“禁用”。 Also allows for a custom disabled class, otherwise defaults to "disabled". 还允许自定义禁用类,否则默认为“禁用”。

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

This is my approach: 这是我的方法:

JavaScript 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 CSS

a[disabled] {
  pointer-events:none;
  cursor:default;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM