jQuery/[removed] Click event on a checkbox and the

2019-02-08 10:28发布

问题:

The code:

$('input.media-checkbox').live('click', function(e){

    e.preventDefault();
    var that = $(this);

    if (that.attr('checked') == 'checked'){

        var m = that.attr('media');
        var mid = 'verify_' + m;
        that.parents('div.state-container').find('ul.' + mid).remove();
        that.attr('checked', false);
    } else {

        var url = AJAX_URL;

        $.ajax({
           type: 'GET',
           url: url,
           dataType: 'html',
           success: function(data){

                that.parents('li').siblings('li.verification').children('div.media-verification').append(data).fadeIn(500);
                that.attr('checked', 'checked');
           }
        }); 
    }

    return false;
});

I am ajaxing in a form, then firing the click event on relevant checkboxes to ajax in another partial if necessary. The form is inserted nicely, and the click events are fired, checking the boxes that need to be checked and firing the second ajax, since the checked attribute of the checkbox was initially false.

What's curdling my cheese is if I UNCHECK one of those boxes. Despite e.preventDefault(), the checked attribute is set to false BEFORE the test, so the if statement always executes the else statement. I've also tried this with $.is(':checked'), so I'm completely baffled.

It appears that unchecked -> checked state reads the original state, but checked -> unchecked doesn't. Any help?

回答1:

B.E., I know it has been a year but I think I found the solution,

The issue here is that the click event actually get's called and runs BEFORE the "checked" property is added to the checkbox input. So the function runs, looks to see if the input has the "checked" attribute, and runs the else condition. THEN the element is given the "checked" property.

I just ran into this as well, and my solution was to bind the function to the change function rather than the click function, as change only fires AFTER the checked property has been updated on the input.

Hopefully this help you, and if not, anyone else who happens to stumble upon this post while experiencing a similar issue.



回答2:

Well, right. You have set the live event, so I think your script might also be responding to setting it as checked, but I can't totally tell what you're trying for here without seeing markup, but here's my rewrite.

$('input.media-checkbox').live('click', function(e){

    if ($(this).is(':checked')) {
        var m = $(this).attr('media');
        var mid = 'verify_' + m;
        $(this).parents('div.state-container')
            .find('ul.' + mid)
            .remove();
        $(this).attr('checked', false);
    } else {
        var url = AJAX_URL;
        var that = this;
        $.ajax({
            type: 'GET',
            url: url,
            dataType: 'html',
            success: function(data) {
                $(that).parents('li')
                    .siblings('li.verification')
                    .children('div.media-verification')
                    .append(data)
                    .fadeIn(500);
                $(that).attr('checked', true);
            }
        }); 
    }
    return false;

});


回答3:

Try using e.stopPropagation() instead of e.preventDefault() and also remove return false. Returning false in jQuery is equivalent to e.stopPropagation() + e.preventDefault(). e.preventDefault() prevents the checkbox from being checked.



回答4:

It seems to be a due to asynchronous requests. The execution goes past $.ajax, before it's success callback fires. When you click the checkbox again, it's state has not yet been updated by the previous request's callback. What you can try is to disable the checkbox control prior to firing the ajax call, and enable it again within the success callback:

that.attr("disabled", "disabled");
var url = AJAX_URL;   
$.ajax({
    type: 'GET',
    url: url,
    dataType: 'html',
    success: function(data){

        that.parents('li').siblings('li.verification').children('div.media-verification').append(data).fadeIn(500);
        that.attr('checked', 'checked');
        that.removeAttr('disabled');
    }
}); 

That will ensure that two successive clicks will not lead to unpredictable behaviour. The other way would be to use a synchronous request, i.e. async: false but that will block the entire browser for it's duration.



回答5:

I think it's due to a weird bug in IE. Check/set attribute defaultChecked along with checked. Try this in your if condition,

if (that.attr('checked')=='checked' || that.attr("defaultChecked")=='checked'){     
      var m = that.attr('media');  
      var mid = 'verify_' + m;
      that.parents('div.state-container').find('ul.' + mid).remove();
      that.attr('checked', false);
      that.attr('defaultChecked', false); 
} else {


回答6:

This is probably only a partial answer, but in your test, $(this).attr('checked') should return true if checked and false if not. So just change your conditional to if (that.attr('checked'))