search

Home  >  Q&A  >  body text

Run JS functions when the document loads and when an element is clicked

I'm trying to write a Tampermonkey script to extend a commercial web application I use. In a very basic sense, some URL appears on the page and I need to extract a number from the URL and then use that number to build a new link and append it to the parent element.

So far I have this but it doesn't work when I click on the element (pagination is just UL) or when the document loads. I know the function works as if I set it to run when I click anywhere in the document it works. When JS reports that a page has loaded, it's almost like the page hasn't fully loaded yet.

(function() {
    'use strict';

    //get the pagination element
    var element = document.getElementsByClassName('pagination-sm');
    element.onclick = createLinks;
    document.onload = createLinks;

    function createLinks() {
    var links = document.querySelectorAll ("a[href*='/Field/POPendingCreate/']");

        for (var J = links.length-1; J >= 0; --J) {
            var thisLink = links[J];
            console.log(thisLink.href);
            var ppon = thisLink.href.match(/\d+/)[0];
            console.log(ppon);

            var a = document.createElement('a');
            var linkText = document.createTextNode("Preview Order");
            a.appendChild(linkText);
            a.title = "Preview Order";
            a.href = "https://website.com/Field/DownloadPendingPO?POPPKeyID=" + ppon + "&co=1&po=" + ppon;
            a.target = "_blank";

            var parentNode = thisLink.parentNode;
            console.log(parentNode);
            parentNode.appendChild(a);

        }
    }

 })();

The UL element looks like this:

<ul uib-pagination="" items-per-page="formData.itemPerPage" class="pagination-sm ng-pristine ng-untouched ng-valid ng-scope ng-isolate-scope pagination ng-not-empty" data-total-items="pendingList.length" data-ng-model="formData.currentPage" data-max-size="10" data-ng-if="!attachmentView &amp;&amp; filteredDocuments.length > 0" role="menu"><!-- ngIf: ::boundaryLinks -->
<!-- ngIf: ::directionLinks --><li role="menuitem" ng-if="::directionLinks" ng-class="{disabled: noPrevious()||ngDisabled}" class="pagination-prev ng-scope disabled"><a href="" ng-click="selectPage(page - 1, $event)" ng-disabled="noPrevious()||ngDisabled" uib-tabindex-toggle="" class="ng-binding" disabled="disabled" tabindex="-1">Previous</a></li><!-- end ngIf: ::directionLinks -->
<!-- ngRepeat: page in pages track by $index --><li role="menuitem" ng-repeat="page in pages track by $index" ng-class="{active: page.active,disabled: ngDisabled&amp;&amp;!page.active}" class="pagination-page ng-scope active"><a href="" ng-click="selectPage(page.number, $event)" ng-disabled="ngDisabled&amp;&amp;!page.active" uib-tabindex-toggle="" class="ng-binding">1</a></li><!-- end ngRepeat: page in pages track by $index -->
<!-- ngIf: ::directionLinks --><li role="menuitem" ng-if="::directionLinks" ng-class="{disabled: noNext()||ngDisabled}" class="pagination-next ng-scope disabled"><a href="" ng-click="selectPage(page + 1, $event)" ng-disabled="noNext()||ngDisabled" uib-tabindex-toggle="" class="ng-binding" disabled="disabled" tabindex="-1">Next</a></li><!-- end ngIf: ::directionLinks -->
<!-- ngIf: ::boundaryLinks -->
</ul>

As I said above, when I set it to run when I click anywhere on the document, the function works as expected. What confuses me even more is that it doesn't work when using document.onload. It's like the page only starts loading data after I start interacting with it. The reason I'm trying to run the function when pagination is clicked is because the page seems to get all the data and store it somewhere (that I can't see) and then just flick the page when pagination is clicked. So I do need to run the function on the generated link on the new page once pagination is clicked.

It seems like I need to delay running document.onload or some other way to understand after the document data is loaded and figure out why it doesn't run when the UL pagination element is clicked?

P粉777458787P粉777458787465 days ago651

reply all(1)I'll reply

  • P粉122932466

    P粉1229324662023-09-16 09:08:56

    Instead of waiting for the page to render and then looping through all elements to append anchor tags. Just use a MutationObserver to handle any elements that are rendered after running your logic.

    JS

    (function() {
        'use strict';
    
        const createLinks = function ( nodeElement ){
            const queryElem = nodeElement.parentElement || nodeElement;
            const links = queryElem.querySelectorAll("a[href*='/Field/POPendingCreate/']");
    
            for ( const link of links || [] ){
                // Skip link if Preview has been attached
                if ( link.createLinkReady ) continue;
    
                // Get numbers from link href
                const [ ppon ] = link.href.match(/\d+/);
    
                // Create an anchor tag
                const a = document.createElement('a');
                a.innerHTML = 'Preview Order';
                a.setAttribute( 'title', 'Preview Order' );
                a.setAttribute( 'href', `https://website.com/Field/DownloadPendingPO?POPPKeyID=${ppon}&co=1&po=${ppon}` );
                a.setAttribute( 'target', '_blank' );
                a.setAttribute( 'rel', 'nofollow' );
    
                // Append anchor tag to parent element
                link.parentElement.appendChild( a );
                link.createLinkReady = true;
            }
    
        }
    
        // Create DOM MutationObserver
        const Observer = new MutationObserver( function( mutationsList ) {
            // Loop through mutations
            for ( const mutation of mutationsList || [] ) {
                // Loop through added nodes
                for ( const node of mutation.addedNodes || [] ){
                    // Run createLinks on node
                    createLinks( node );
                }
            }
        });
    
        // Observe DOM for new elements starting from document.body
        Observer.observe( document.body, { childList:true, subtree:true } );
    
        // Process links that have been rendered
        createLinks( document.body );
     })();
    

    reply
    0
  • Cancelreply