0

Hey I have the following function which works great in JQuery, but for many reasons I require it in plain JS.

$('audio').on("play pause ended", function () {
    document.title = document.title.replace("\u25B6", "")
    $("audio").each(function (index) {
        if (!this.paused) {
            document.title = "\u25B6 " + document.title.replace("\u25B6 ", "")
            return false;
        }
    })
});

I've attempted to convert it to plain JS (see below) however it's just coming up with the following error: TypeError: undefined is not a function (evaluating 'sound.addEventListener')

var sound = document.getElementsByTagName('audio');
sound.addEventListener('play pause ended', function () {
    document.title = document.title.replace('\u25B6', '')
    sound.each(function (index) {
        if (!this.paused) {
            document.title = '\u25B6 ' + document.title.replace('\u25B6 ', '')
            return false;
        }
    })
});
Tushar
  • 85,780
  • 21
  • 159
  • 179
user1887683
  • 133
  • 2
  • 7
  • The error is telling you that `sound` is undefined. – Evan Davis Jun 10 '15 at 13:52
  • 1
    Youre `getElementsByTagName` returns a nodeList, not an `HTMLElement` or `DOMNode`, you need to loop through that list and attach the listener to any/all of the elements you want to listen for it. – prodigitalson Jun 10 '15 at 14:03
  • While that is correct, ealier I had the line as var sound = document.getElementsByTagName('audio')[0]; which displays single HTMLElement correct? and the same error applies. – user1887683 Jun 10 '15 at 14:31

1 Answers1

2

The following should do the trick:

var sounds = document.getElementsByTagName('audio');
/* Loop through the nodelist - this is **not** an array */
for(var i = 0; i < sounds.length; i++){
    /* Get the item in your nodelist. This **is** an element. */
    var sound = sounds.item(i);
    /* Now add your event listener here - You can only add one at a 
     * time, though. So I decided to make the event a separate  
     * function and attach it multiple timers. */
    function eventHandler(){
        document.title = document.title.replace('\u25B6', '')
        if (!sound.paused) {
            document.title = '\u25B6 ' + document.title.replace('\u25B6 ', '')
            return false;
        }
    }
    sound.addEventListener('play', eventHandler, false);
    sound.addEventListener('pause', eventHandler, false);
    sound.addEventListener('ended', eventHandler, false);
}

Two things: document.getElementsByTagName returns an HTMLNodeList which is not an array. It can be looped through because it has a length property, but it cannot use the forEach(since it also has a function called item, which is used to get the element at the provided index of the nodelist).

Secondly, this does not refer to your item in a forEach, you need to pass a parameter to your forEach function that you can reference (aka array.forEach(function(item){}); where your item would be referenced by item). But like I said, that won't make a difference here as a nodeList is not an array.

Updated

It just came to me that there is a simple way to attach all events, so I amended it appropriately.

somethinghere
  • 16,311
  • 2
  • 28
  • 42
  • That's perfect, that's so much - you're a life saver :) – user1887683 Jun 10 '15 at 14:33
  • I have one question, do you know how I could get this to apply with audio tags used within an iFrame? – user1887683 Jun 10 '15 at 14:43
  • I think you could (I say _could_ as I have not tried this) use the iframe and then dig into it's contents and body, but I am not sure. Have a look at this and hopefully it helps you on your way: http://stackoverflow.com/questions/926916/how-to-get-the-bodys-content-of-an-iframe-in-javascript#answer-11107977 – somethinghere Jun 10 '15 at 14:49