Mohamed Ali
Mohamed Ali

Reputation: 13

2 datetimepicker with same class problems

I have a template generator, which can create a string template with some variables which can be modified later, for example: “Dear passenger, your flight @@FNumber@@ date has been changed from @@OldDate@@ to @@NewData@@”. This part has no issue at all. There’s another page which fill the template to send the text as SMS to the users, so the user will select the template title which is generated by the previous section, then I create dynamic controls which will hold the variables values, for the earlier example: I will create 3 inputs to replace @@FNumber@@ with the actual/real flight number, and the same with dates, and here is the issue as I create DateTimePicker for date fields, and when I change any value of these dynamic controls, it should be reflected on the preview input box, but I have an issue with the DateTimePicker control.

when page contain more than one DateTimePicker and the first is changed . like this image DateTimePicker images the function apply on all another DateTimePicker example :

    $('.datetimepicker2').on('dp.hide', function () {
     alert('hide')    
     })

this alert appear more than one time
if i changed the second DateTimePicker it works correctly and the alert appear only one

any advise???

Upvotes: 0

Views: 60

Answers (1)

Daniel
Daniel

Reputation: 717

Problem

Are the $('.datetimepicker2') being appended dynamically to the page? If so, is the 'dp.hide' event listener being added for each created $('.datetimepicker2')? If that's the case, then we're doing the binding of the event listener in the wrong way.

Take a look at this wrong example with dynamically created buttons:

$(document).on('ready', function () {
    // functions 
    function bindButtonClick (i) {
        $('button').on('click', function () {
            alert('Click listener no ' + i);
        });
    }
    
    function appendButtons (numButtons) {
        var $button,
            i;
        
        for (i = 0; i < numButtons; i) {
            $button = $('<button>Button' + ++i + '</button>')
                .appendTo('.main-container');
                
            bindButtonClick(i);
        }
    }
    
    // init
    appendButtons(3);
});
<!-- Scripts -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<!-- HTML -->
<div class="main-container"></div>

Basically what's happening is that every time I create a $button, I'm binding a 'click' event NOT to the created $button but to that created button and all the previous $button's created, because I'm doing the binding with the selector 'button', jQuery is selecting all the buttons in the DOM at the moment, and binding the 'click' event listener to all of them.

If we debug this in our minds, we can understand that when we create our 1st $button, it binds the 'click' listener to that button using the 'button' selector, then it created the 2nd $button and, once again, binds the 'click' listener to both the newly created $button and the previous one, because the used selector 'button' is catching both of them, so the 1st $button has now 2 click listeners, while the 2nd only have 1, then it created the 3rd and last $button and, once again , binds another 'click' listener to the newly created $button, and the previous ones as well! In the end we have the 1st $button with all the 3 click listeners, the 2nd $button with the last 2 click listeners and the 3rd $button with the last click listener.

We have a couple of solutions that can solve the problem:

Solution 1

Instead of binding the click listener using the 'click' selector, we can bind it directly to the reference of the newly created $button:

bindButtonClick($button, i);

And

function bindButtonClick ($button, i) {
    // the click listener is binded directly to the created $button
    $button.on('click', function () {
        alert('Click listener no ' + i);
    });
}

Here is a working example of Solution 1:

$(document).on('ready', function () {
    // functions 
    function bindButtonClick ($button, i) {
        /** 
         * instead of using the general selector $('button'), 
         * we can use the newly created $button reference
         **/
        
        $button.on('click', function () {
            alert('Click listener no ' + i);
        });
    }
    
    function appendButtons (numButtons) {   
        var $button,
            i;
        
        for (i = 0; i < numButtons; i) {
            $button = $('<button>Button' + ++i + '</button>')
                .appendTo('.main-container');
               
            bindButtonClick($button, i);
        }
    }
    
    // init
    appendButtons(3);
});
<!-- Scripts -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<!-- HTML -->
<div class="main-container"></div>

Solution 2

Instead of binding a 'click' listener for each individual $button, we can bind all of them after the creation of the buttons. Since all 3 buttons would be in the DOM at that time, we could use our general selector 'button' to bind the click listener to all of them:

$(document).on('ready', function () {
    // functions 
    function appendButtons (numButtons) {
        var $button,
            i;
        
        // create the buttons
        for (i = 0; i < numButtons; i) {
            $button = $('<button>Button' + ++i + '</button>')
                .appendTo('.main-container');
        }
        
        // bind the clicks after the buttons creation
        $('button').on('click', function () {
            alert('Button\'s click listener');
        });
    }
    
    // init
    appendButtons(3);
});
<!-- Scripts -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<!-- HTML -->
<div class="main-container"></div>

Upvotes: 1

Related Questions