Run JS functions when the document loads and when an element is clicked
P粉777458787
P粉777458787 2023-09-15 14:26:54
0
1
646

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粉777458787
P粉777458787

reply all(1)
P粉122932466

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 );
 })();
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template