jQuery multiple selector alert only first time

746 Views Asked by At
//Function called by sigle element or multiple times (see below)
$('[id^=old_]').change(function(){
    var check = $(this).prop('checked') ? true : false;

    if(check){
         /* stuff here */
    }else{
        var reprise = confirm('Are you sure?');

        if(reprise){
            /*  do stuff */
        }else{
            $(this).prop('checked', true);  
        }
    }
});

//Function called on "select all/deselect all"
$('#span_descr > div:last-child').on('click', 'span:first-child', function(){
     $('[id^=old_]:not(:checked)').click();
}).on('click', 'span:last-child', function(){
    $('[id^=old_]:checked').click();
});

My problem is that on "deselect all" click I get an alert/confirm message for each deselected items. Is there a way to avoid that and get only once this message?

6

There are 6 best solutions below

1
On

Check out jQuery one().

jquery

$('selector').one('click', function(event){....});

jSFiddle

2
On

Instead of using .click() to toggle your check boxes, use .prop('checked', ...), like this:

//Function called on "select all/deselect all"
$('#span_descr > div:last-child').on('click', 'span:first-child', function(){
     $('[id^=old_]:not(:checked)').prop('checked', true);
}).on('click', 'span:last-child', function(){
    $('[id^=old_]:checked').prop('checked', false);
});

This should avoid triggering your .change() handler, which is causing the wave of alerts.

0
On

how are you?

Please, try this little modification to your code:

//Function called by single element or multiple times (see below)
var alreadyReprised = null;
$('[id^=old_]').change(function(){
    var check = $(this).prop('checked') ? true : false;

    if(check){
         /* stuff here */
    }else{

        var reprise = alreadyReprised || confirm('Are you sure?');
        if(reprise){

            if(alreadyReprised === false) {
                alreadyReprised = true;
            }
            /*  do stuff */
        }else{
            $(this).prop('checked', true);  
        }

    }
});

//Function called on "select all/deselect all"
$('#span_descr > div:last-child').on('click', 'span:first-child', function(){
     $('[id^=old_]:not(:checked)').click();
}).on('click', 'span:last-child', function(){
    alreadyReprised = false;
    $('[id^=old_]:checked').click();
    alreadyReprised = null;
});

Regards.

0
On

Try this

//Function called by sigle element or multiple times (see below)
$('[id^=old_]').change(function(){
    var check = $(this).prop('checked') ? true : false;

    if(check){
         /* stuff here */
    }else {
        var reprise = null;

        if($(this) == ('[id^=old_]:first-child'))
          reprise = confirm('Are you sure?');

        if(reprise){
            /*  do stuff */
        }else{
            $(this).prop('checked', true);  
        }
    }
});

//Function called on "select all/deselect all"
$('#span_descr > div:last-child').on('click', 'span:first-child', function(){
     $('[id^=old_]:not(:checked)').click();
}).on('click', 'span:last-child', function(){
    $('[id^=old_]:checked').click();
});
0
On

I guess you just need to take all the stuff that has to be executed outside of the click handler, so that it can be referenced from other code as well. It is not pretty, but works:

//Function called by sigle element or multiple times (see below)
$('[id^=old_]').change(function(){
    var check = $(this).prop('checked') ? true : false;

    if(check){
         onSelected(this);
    }else{
        var reprise = confirm('Are you sure?');
        if(reprise){
            onDeselected(this);
        }else{
            $(this).prop('checked', true);  
        }
    }
});

function onSelected(checkbox){
    /* stuff here */
    console.log("selected");
}

function onDeselected(checkbox){
    /*  do stuff */
    console.log("deselected");
}

//Function called on "select all/deselect all"
$('#span_descr > div:last-child').on('click', 'span:first-child', function(){
     $('[id^=old_]:not(:checked)').click();
}).on('click', 'span:last-child', function(){
    if(confirm('Are you sure?')){
        var checked = $('[id^=old_]:checked');
        checked.prop('checked', false);
        checked.each(function(index, elem){
            onDeselected(elem);
        });
    }
});

Check the fiddle

An alternative solution would be to preventDefault() all click events on the checkboxes and check/uncheck them yourself. This would allow you to better separate the concepts "checkbox being clicked" and "checkbox being selected" which would bring about cleaner code. However, I'm not very fond of preventing default behavior, because you never really know what the default behaviour is.

0
On

One way you could do it is by using eventData.

Following is an example that passes data to the change handler from the checkAll checkbox. This allows you to see if that data exists thus knowing if the change event was user triggered or triggered externally

var $checks = $(':checkbox:not(#check_all)').change(function(e ,isTriggerEvent, isChecked){
    if(!isTriggerEvent){
       if(this.checked)
       alert('Manually changed') ;
       /* see if check_all needs to be changed when user checks or unchecks a checkbox */  
        var allChecked = !$checks.filter(':not(:checked)').length;
        $('#check_all').prop('checked',allChecked);    
    }else{
        /* match checked state to "check_all" state */
        this.checked = isChecked;
    }       
});

$('#check_all').change(function(e){ 
    /* 1st param in eventData tells other checkboxes is a trigger, 2nd param to send state */   
    $checks.trigger('change',[true, this.checked]);        
});

Reference: trigger() Docs

Note that all jQuery event handlers allow for passing data parameters using trigger

DEMO