Booyah
Booyah

Reputation: 111

Modifying querySelector to apply to all page elements (querySelectorAll)

I am trying to make a generalized routine which will play a sound before redirecting to the specified href of a link. I'm trying to keep this as dynamic as possible to avoid having to add onclick events to each link manually, etc.

From other code on stackoverflow and elsewhere, I've managed to find almost exactly what I'm looking for.

    document.querySelector('.playsound').onclick = function (evt) {
        evt = evt || window.event;

        playThenRedirectTo('sndButton', this.href);

        // prevent the link from being followed, until we want to later on
        if (evt.preventDefault) {
            evt.preventDefault();
        } else {
            evt.returnValue = false;
        }
    }

    function play_single_sound(target) {
        document.getElementById(target).play();
    }
    function newPage(url) {
        location.href = url;
    }
    function playThenRedirectTo(audioTarget, url) {
        var time = 0;

        play_single_sound(audioTarget);

        setInterval(function () {
            var end = document.getElementById(audioTarget).played.end(0);
            if (end > time) {
                time = end;
            } else {
                newPage(url);
            }
        }, 250);
    }

This works for the first element on the page. The sound file is played prior to redirection. However I'm not sure how to make this apply to all elements with css class matching playsound as right now it only applies to the first.

I'm assuming querySelectorAll and some sort of forEach will be required, but I don't know what the syntax would be to use it. Any suggestions would be much appreciated!

Upvotes: 2

Views: 92

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 371193

While you could use querySelectorAll to add a listener to every <a> on the page, you might consider event delegation instead: add a single click listener to the document, and when something is clicked, check if the target is an a. If so, call playThenRedirectTo:

document.addEventListener('click', (e) => {
  if (!e.target.matches('a')) return;
  // if you only want `.playSound` `a`s to trigger this behavior, instead use
  // if (!e.target.matches('a.playSound')) return;

  playThenRedirectTo('sndButton', e.target.href);
  if (e.preventDefault) {
    e.preventDefault();
  } else {
    e.returnValue = false;
  }
});

The querySelectorAll version involves using forEach to iterate over all elements, and attaching a listener to each:

Array.prototype.forEach.call(
  document.querySelectorAll('a.playsound'), // or whatever selector you want
  playsound => playsound.onclick = e => {
    playThenRedirectTo('sndButton', playsound.href);
    if (e.preventDefault) {
      e.preventDefault();
    } else {
      e.returnValue = false;
    }
  }
);

(although on newer browsers, you can forEach directly over a NodeList, such as returned by querySelectorAll, for that to work reliably for website visitors, you'd need a polyfill, thus the call of the Array method)

Upvotes: 1

Related Questions