defunkt / jquery-pjax

pushState + ajax = pjax
https://pjax.herokuapp.com
MIT License
16.73k stars 1.97k forks source link

'pjax:end' event fires multiple times #586

Closed keithpickering closed 7 years ago

keithpickering commented 9 years ago

I'm trying to use this plugin extremely simply to load html content into a div as tabs are selected. I'm trying to run some functions each time a tab is changed and the content is loaded:

function loadTab(tab) {
    var url = tab + '.html';

    console.log('Loading template "' + url + '"');

    var pjax = $.pjax({url: url, container: '#main-content'}, {
        replace: true
    });

    $(document).on('pjax:end', function(data, status, xhr, options) {
        console.log('Successfully loaded "' + url + '"');

        initGraph();
        initRangeInputs();
        initCircleProgress();
    });
}

The problem is that these events seem to "stack", so each time a new tab is selected, the pjax:end event runs for all the tabs that have been clicked in that particular session. This means these three functions are being run potentially dozens of times which obviously leads to some issues.

Is there anything I can do about this? Thanks!

mislav commented 9 years ago

It might not be that pjax:end events run so often. It looks like you're attaching a new pjax:end event observer each time loadTab() is called. If you call it 5 times, each pjax:end event will be logged 5 times in the console, even though it ocurred once.

Shade- commented 8 years ago

Bumping an old issue to share my experience with a similar situation. I'm developing a plugin which enables pjax navigation on any MyBB forum. While the core JSes do not seem to interfere with it as it does not use event delegation at all, another plugin I'm developing performs a massive use of event delegation. I came across many JS errors before realizing my custom functions were stacked and run multiple times, so I adapted the code of the plugin in order to make it compatible with pjax.

This was a huge mistake because I dropped the development due to personal commitments and now that I had some time to get back on track I've been facing the exact same problem with an enhanced version of yet another plugin of mines. I should have thought about adapting the pjax implementation instead of making a patch for that particular addon. So I ended up writing down a simple yet apparently effective line of code into my pjax call before any other event is called:

$('body').off();

This little bastard just drops any event delegation previously attached onto the 'body' selector (which is the target of all my delegations), ensuring no duplicates at all. It feels like a stupid conclusion from a noob developer (and given it's quite a inconstant hobby for me, I might be one), but it is working just fine for me in my early tests and should work for you too with some adaptation. Just call .off() onto the document selector and you're ready to go.