简体   繁体   中英

How to make sure that all events are unattached when called multiple times in Javascript?

I'm using dragswipe, a plugin from here . It works perfectly fine. However, I have a requirement to do dynamic carousels. So, every time a user changes something on a page, the carousels get updated dynamically. I thought I could just recall the plugin to update the element, but somehow when I dragged the carousel the functional gets called multiple times.

For example, I do this to initialise the plugin.

function init() {

    $('#carousel').dragswipe({
     width: 320,
     current_page_element: '#current_page',
     total_pages_element:'#total_pages'
    });
}

So after the page is updated via ajax I have a callback to call this method again like this

function callback() {
 init();
}

Everything should is updated perfectly fine, but when I started dragging. The carousel skips some pages. I thought I had to unbind all the events so I tried this. $('#carousel').unbind() but the problem still persists.

Here's the source code when the plugin is initialised.

$.fn.dragswipe = function(options) {

        options = $.extend({
            offset: 0,
            turn_threshold: 0.1,
            current_page: 0         
        },options)
        this.each(function() {

            option = $(this).hammer({
                drag_vertical: false,
                swipe_time: 20
            });


            // start a drag. 
            // if we're moving left or right, set our initial distance to 0.
            $(this).bind('dragstart',function(ev) {
                console.log('dragstart');
                if (ev.direction=='left' || ev.direction=='right') {
                    drag_distance = 0;
                }
            });         

            // while dragging, change the dragging distance based on how far a user has dragged.
            $(this).bind('drag',function(ev) {
                console.log('drag');
                if (ev.direction=='left' || ev.direction=='right') {
                    drag_distance = ev.distanceX;   
                    var options = CONFIGS[$(this).data('dragswipe_id')];
                    $(this).updateOffset(options.offset+drag_distance);

                }
            });     

            $(this).bind('dragend',function(ev) {

                console.log('dragend');
                if (ev.direction=='left' || ev.direction=='right') {
                    var options = CONFIGS[$(this).data('dragswipe_id')];

                    if (Math.abs(drag_distance / options.width) > options.turn_threshold) {
                        if (ev.direction=='left') {
                            options.current_page++;
                        }
                        if (ev.direction=='right') {
                            options.current_page--;
                        }
                    }

                    // store modified options
                    CONFIGS[$(this).data('dragswipe_id')] = options;
                    console.log(options.current_page);
                    $(this).gotoPage(options.current_page,true);

                }
            });

            // set the dragswipe ID used to look up config options later.
            $(this).data('dragswipe_id',CONFIGS.length);

            // store config options.
            CONFIGS[$(this).data('dragswipe_id')] = options;
        });

    }

Which I see nothing wrong with the plugin, but maybe I'm missing something obvious.

UPDATED

I have created the example in jsfiddle , but it's not working just in case anyone can fix the problem. Also, on the plugin site itself. The problem can be reproduce by running this code to initialise the plugin multiple times. After running the code twice, when you drag the page it goes to the last page instead of the second page.

$('#carousel').dragswipe({
 width: 320,
 current_page_element: '#current_page',
 total_pages_element:'#total_pages'
});

Have you tried turning it off and on again?

Dragswipe has a removeDragswipe() method that does a little bit more than just unbinding, and it also explicitly only unbinds events that are related to dragswipe itself so it won't mess up any other events that may have been bound.

So instead of unbind() , do this:

function callback() {
  $('#carousel').removeDragswipe();
  init();
}

As discussed in the comments, this doesn't work because it seems that even after unbinding all the events, after re-binding them by activating the plugin again the events seem to fire an extra time.

What does seem to be a workaround is to actually rebuild the entire element so that no events can linger:

function callback() {
  $('#carousel').removeDragswipe();
  rebuildCarousel();
  init();
}

function rebuildCarousel() {
    var wrapper = $('#carousel').parent;
    var html = parent.html();
    $('#carousel').remove();
    wrapper.html(html);
}

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