简体   繁体   中英

preventDefault() `click` in Knockout.js 3

I have a data-bind="click: ..." event in Knockout.js and I'm trying to disable it whenever a disabled class is presence in the element.

<span class="disabled" data-bind="click: alerting">Two</span>

I'm trying this without success:

$('.disabled').click(function(e){
    e.preventDefault();
});

Reproduction online

I prefer to do it by using a classname as this way I can handle both the styling of the element and the interaction with it for multiple elements in the site.

The issue here is that there's no guarantee as to which click handler is going to run first. In this case, the knockout click binding is executing before the jquery handler.

Given that you're working with knockout, the "proper" way to do this would be for the viewmodel to handle everything, and not rely on something external, such as jQuery, to prevent the click from happening.

In your case, the viewmodel might look like this:

var viewModel = {
    disabled: ko.observable(false),
    alerting: function(data, e) {
       if (!this.disabled())
           alert("two");
    }
};

You then just update the disabled observable to enable/disable the click handler. You could also make use of this observable to apply different styling to elements that should be disabled, eg adding the disabled style, rather than using the style to control the knockout behaviour.

There's a few ways I could think of for you to deal with this requirement.

I've put a few options in this working example for you to look at: http://plnkr.co/edit/t1jG3JmsywxteRyNNKS4?p=preview .

I've also forked your JSFiddle here http://jsfiddle.net/8pa84cmu/1/

<p>Option 1 - Applying the disabled class, leave button clickable but check for class in click handler and do nothing</p>
<button class="disabled" data-bind="click: RegisterClick">Click</button>
<hr/>
<p>Option 2 - An enabled button doing what the click handler asks</p>
<button class="enabled" data-bind="click: RegisterClick">Click</button>
<hr/>
<p>Option 3 - A binding using a boolean to apply the class name if required and disabling it if required</p>
<button data-bind="click: RegisterClick, css: { disabled }, disable: disabled">Click</button>
<hr/>
<p>Option 4 - A binding just dealing with enabling / disabling</p>
<button data-bind="click: RegisterClick, enable: IsEnabled">Click</button>
var ViewModel = function() {
  this.RegisterClick = function(model, event) {
    if (event.target.className === "disabled") {
      return;
    }

    console.log("Clicked");
  }

  this.disabled = true;
  this.IsEnabled = false;
}

window.onload = function() {
  ko.applyBindings(new ViewModel());
}

You should use disabled attr to disable the element. You can deal with visual styling using this:

a:disabled {
    color: red;
}

You can also, check the disable class inside knockout's function (not recommend, just an example). Like this http://jsfiddle.net/mCxjz/81/

Here is how you would control styling of an element, and have a callback take that styling into account. If you had 20 elements that you wanted to style together, you would use the same observable for each of them. This example makes three clickable spans, and disables them after 2.5 seconds. You can see the styling change.

 var viewModel = { isDisabled: ko.observable(false), alerting: function(data, event) { if ($(event.target).hasClass('disabled')) return; alert(event.target.innerHTML); } }; ko.applyBindings(viewModel); setTimeout(function () { viewModel.isDisabled(true); }, 2500); 
 .clickable { border-radius: 5px; padding: 5px; background-color: lightgreen; cursor: pointer; } .disabled { background-color: lightgray; cursor: not-allowed; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> <span class="clickable" data-bind="click: alerting, disabled: isDisabled, css: {disabled: isDisabled}">One</span> <span class="clickable" data-bind="click: alerting, disabled: isDisabled, css: {disabled: isDisabled}">Two</span> <span class="clickable" data-bind="click: alerting, disabled: isDisabled, css: {disabled: isDisabled}">Three</span> 

I updated to your code to fit your requirements. What I understand from jQuery is that executing .click only binds more events to the elem. What the following code does is it overrides the exiting click handler.

$._data($(elem)[0], 'events').click[0].handler = function() {return;}

Should you want to get back your old function, probably save it in a var and reassign it later. Hope this helps.

http://jsfiddle.net/mCxjz/84/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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