Search code examples
javascriptrandomhrefstr-replacegetelementbyid

How do I randomly replace the HREF of a specific URL? innerHTML affects lazy loading


Ok, I've been hitting my head for over a week now and I can't take it anymore.

My goal here is to randomly replace the HREF of a specific URL on any given page.

For example: https://example.com/offer/free-pizza/

There are versions of my URL that contain query string parameters, i.e. https://example.com/offer/free-pizza/?sliceapp that I want to ignore, that's why I explicitly use regex to call out the quotation marks for my specific URL in this line:

str.replace(/"https:\/\/example\.com\/offer\/free-pizza\/"/g

I'm deploying the code below using a Custom HTML tag in Google Tag Manager. Unfortunately, the links do not contain IDs, so I can't specifically call upon those, so I'm looking at everything contained within the body of the page, in other words, , which is the body of each page I'm working with. Everything works exactly as expected with the code below, except that the lazy-loaded images on the page do not appear.

<script>
  function myfunction(){
  var str = document.getElementById("main").innerHTML; 
  var res = str.replace(/"https:\/\/example\.com\/offer\/free-pizza\/"/g, function() {
return ['https://example.com/somewhere-else/', 'https://example.com/offer/free-pizza/'][Math.floor(Math.random() * 2)] 
return Math.floor(Math.random() * (max - min + 1)) + min;
});
  document.getElementById("main").innerHTML = res;
  }
</script>

From my troubleshooting, I know the issue has something to do with using innerHTML to return the entire . Something clearly doesn't work there with the images and the returned HTML. So I set off to instead just look at the individual URLs on the page, not the whole section, so I could bypass the image issue altogether.

I must have written tens of dozens of variations at this point to try and accomplish this, but nothing seems to work.

var els = document.querySelectorAll("a[href^='https://example.com/offer/']");
for (var i = 0, l = els.length; i < l; i++) {
  var el = els[i];
  el = el.replace(/"https:\/\/example\.com\/offer\/free-pizza\/"/g, function() {
return ['https://example.com/somewhere-else/', 'https://example.com/offer/free-pizza/'][Math.floor(Math.random() * 2)] 
return Math.floor(Math.random() * (max - min + 1)) + min;
})};
</script>

I'm hoping that someone much smarter than me can see my obvious flaws and point me in the direction of how I can write this in a much more effective way, given the context and my goal.

Thank you.


Solution

  • The problem with replacing the whole document's innerHTML is, that you might remove (and replace) DOM nodes that have attached event listeners to them, which makes them void. I guess the lazy loading mechanism makes use of this.

    Thus, instead of replacing the whole document's innerHTML, you could just iterate over the anchor tags and replace the href property:

    document
      .querySelectorAll("a[href^='https://example.com/offer/']")
      .forEach(function (el) {
        el.href = el.href.replace(/https\:\/\/example\.com\/offer\//g, replaceFn);
      });
    
    function replaceFn() {
      return [
        'https://example.com/somewhere-else/', 
        'https://example.com/offer/free-pizza/'
      ][Math.floor(Math.random() * 2)];
    }