2

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.

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
Trax
  • 1,445
  • 5
  • 19
  • 39
  • try adding a `setTimeout()`. Might also be able to use MutationObserver API depending on how page actually works – charlietfl Dec 25 '18 at 15:46
  • I'm using timeout, I was looking for a less dirty way to do it. – Trax Dec 25 '18 at 15:50
  • Can also use setInterval and check for conditions within dom and clear interval once met. Not really enough known for more concise answers – charlietfl Dec 25 '18 at 15:51
  • On a higher level can also use ajax interceptors if that is how content is being changed but that requires studying the network requests and is not a generic approach – charlietfl Dec 25 '18 at 15:58

1 Answers1

3

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?.

Brock Adams
  • 90,639
  • 22
  • 233
  • 295