Search code examples
javascriptjquerygreasemonkeyuserscriptstampermonkey

How to get a Tampermonkey script to wait for page to finish after a hashchange event?


I'm writing a Tampermonkey script and I set up a listener for hashchange.
Inside that listener, I call a function that manipulates the DOM. The problem is that the function is called before the page is fully loaded.

The page is not completely reloading when switching from one section to another so on load would only work once, that's why I'm listening for hashchange instead of load.

window.addEventListener('hashchange', function (e) {
    if (!/step=view&ID=/.test(location.hash)) {
        //TODO clean up if leaving active trade
        return
    }
    console.log('hash changed', e)
    setup()
});

function setup() {
    //wait for page load here
    $('.myclass').after(<span>foo</span>);
}

I tried adding on load inside setup but that did nothing.

Edit:

Adding a listener for load outside setup would also work only once if going to the exact link, so that's not an option either.


Solution

  • This is a job for waitForKeyElements, or MutationObserver or setTimeout

    On almost all such pages, waitForKeyElements by itself is sufficient, no hashchangelistener needed:

    // ==UserScript==
    // @name     _spans of foo
    // @match    *://YOUR_SERVER.COM/YOUR_PATH/*
    // @require  https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js
    // @require  https://gist.github.com/raw/2625891/waitForKeyElements.js
    // @grant    GM_addStyle
    // @grant    GM.getValue
    // ==/UserScript==
    //- The @grant directives are needed to restore the proper sandbox.
    /* global $, waitForKeyElements */
    
    waitForKeyElements (".myclass", setupMyClass);
    
    function setupMyClass (jNode) {
        jNode.after ('<span>foo</span>');
    }
    

    Since your added <span>foo</span>s are apparently not persisting after hashchange, then this technique is probably all you need.


    However, if the page is one that reuses the .myclass nodes (¿but somehow destroys your spans?) instead of recreating them, then use a technique like that shown in this other answer.

    In this scenario, MutationObserver might be a better choice. But, that depends on details not provided in your question.


    See, also, How do I reload a Greasemonkey script when AJAX changes the URL without reloading the page?.