Only change from Play to Pause if the audio link is working

Right now, any letters I type into the text input will cause the Play button to change to Pause.

Could I set it up so that the Play button would only change to the Pause button if the audio link is working?

https://jsfiddle.net/vhgL96se/62/


(function iife() {
    "use strict";
    const player = document.getElementById("player");
    const button = document.getElementById("button");
    const value = document.getElementById("input");
    const sent = document.getElementById("sent");
    const input = document.getElementById("clear");
    let canPlay = false;

    function playPauseIcon(play) {
        if (!canPlay) {
            return;
        }
        if (play) {
            button.classList.add("is-playing");
        } else {
            button.classList.remove("is-playing");
        }
    }
    button.addEventListener("click", function () {
        if (!canPlay) {
            return;
        }
        if (player.paused) {
            player.play();
            playPauseIcon(true);
        } else {
            player.pause();
            playPauseIcon(false);
        }
    });
    button.addEventListener("mousedown", function (evt) {
        if (evt.detail > 1) {
            evt.preventDefault();
        }
    }, false);
    sent.addEventListener("click", function () {
        player.src = value.value;
        player.volume = 1.0;
        playPauseIcon(true);
    });
    input.addEventListener("click", function () {
        value.value = "";
        button.classList.remove("is-playing");
        player.pause();
        canPlay = false;
    }, false);
    player.onloadstart = function () {
        if (value.value !== "") {
            canPlay = true;
            playPauseIcon(true);
        }
    };
}());

play() returns a promise. So you can throw if it fails to play (this is not tested, sorry, but I think it is close to correct):

button.addEventListener("click", function () {
  if (!canPlay) return;

  if (player.paused) {
    player.play().catch(err => throw new Error(`I can't play for some reason`));
    ...
1 Like

Was I supposed to add that to here?
https://jsfiddle.net/vhgL96se/70/

    button.addEventListener("click", function() {
        if (!canPlay) {
            return;
        }
        if (player.paused) {
            player.play().catch(err =>
                throw new Error(`I can't play for some reason`));
            player.play();
            playPauseIcon(true);
        } else {
            player.pause();
            playPauseIcon(false);
        }
    });

Yes, remove the extra player.play though

I did that, I removed the extra [player.play]

How do I fix the red error?

Because of that, the code is not working.
https://jsfiddle.net/vhgL96se/71/


    button.addEventListener("click", function() {
        if (!canPlay) {
            return;
        }
        if (player.paused) {
            player.play().catch(err =>
                throw new Error(`I can't play for some reason`));                    
            playPauseIcon(true);
        } else {
            player.pause();
            playPauseIcon(false);
        }
    });

In the event of encountering the .catch() handler, the error has already been thrown. That’s kind of the point of it. So your code for that line should be:

player.play().catch(err => console.error(`I can't play:`, err)); 

The error has been thrown by the Promise, and the catch() has placed the result of the possible error into your err parameter.

1 Like

If the value is an incorrect stream link, the play button still changes to pause.

This is what I was trying to prevent from happening.

h://hi5.1980s.fm/;
https://jsfiddle.net/vhgL96se/82/

button.addEventListener("click", function() {
        if (!canPlay) {
            return;
        }
        if (player.paused) {
            player.play().catch();
            playPauseIcon(true);
        } else {
            player.pause();
            playPauseIcon(false);
        }
    });

Of course it does. Because you aren’t actually doing what you think you’re doing. Look into javascript Promises, they’re a powerful mechanism. Instead of doing what you’re doing here:

        if (player.paused) {
            player.play().catch(err =>
                throw new Error(`I can't play for some reason`));                    
            // Here, whether or not the player errored, you are going ahead and doing the playPauseIcon
            playPauseIcon(true);
        }

Promises have a couple of follow-up functions: you’ve met .catch(), used to field errors, but what do you do with successful completion? That’s where you do .then():

if (player.paused){
  player.play()
        .then(() =>{
          // handle a successful play()
          playPauseIcon(true);
        })
        .catch(err=>{
          // handle a failed play(), and display your error message.
          console.error("Well, CRAP. I died: ", err)
          playPauseIcon(false);
        });
} else ...
2 Likes

How do I clean it up? Fix the errors?

https://jsfiddle.net/vhgL96se/86/


    button.addEventListener("click", function() {
        if (!canPlay) {
            return;
        }
        if (player.paused) {
            player.play().then(); {
                playPauseIcon(true);
            } catch (err) {
                playPauseIcon(false);
            }
        } else {
            player.pause();
            playPauseIcon(false);
        }
    });

Wow. That’s kind of ugly. Your code and mine are a little different. In essence, here’s what I gave you:

player.play()
      .then(/* function to handle the successful complete */)
      .catch(/* function to handle the failed complete */ );

THAT IS ALL ONE LINE. It is a single call, and two callbacks. I set up the promise, and I have two conditional handlers. Your code, on the other hand, does this:

player.play()
      .then(); /* <-- You aren't handling the successful at all! */ 
      { playPauseIcon(true) } /* And the js doesn't even KNOW what to do with this. */
      catch(err) { /* By this point, things have gotten ugly. */}

Refer back to my code. What you have defined OUTSIDE the then() should be the function body inside of the .then(), and the catch() is chained right to that:

player.play().then().catch();

The error is still there though:
https://jsfiddle.net/vhgL96se/88/

    button.addEventListener("click", function() {
        if (!canPlay) {
            return;
        }
        if (player.paused) {
            player.play()
            .then()
            .catch(); {
                playPauseIcon(true);
            } catch (err) {
                playPauseIcon(false);
            }
        } else {
            player.pause();
            playPauseIcon(false);
        }
    });

And you still have that random catch() going on after the catch(). So yeah, there are going to be errors. Again, look back at my post a few back. The code goes:

if(player.paused){
  player.play() // <-- THIS LINE IS THE PROMISE
        .then(function() { // <-- This line handles a successful result. Note that, 
                           //    by starting it with a period, it continues from the last function call.
          playPauseIcon(true);
          // Do whatever other success handling we need.
        }) // <-- THIS LINE ENDS THE SUCCESS CALLBACK
        .catch(function(err){ // <-- This line starts the failure result. Again, it starts with a period,
                              // so it is chaining directly onto the .then() above.
          playPauseIcon(false);
          console.error("Well CRAP. I failed on play(). Here's why:", err);
        }); // <-- AND THIS LINE ENDS THE FAILURE CALLBACK. Also, ends the Promise handling.
} // <-- And this ends the player.paused if statement

Unused ‘err’.
}).catch(function (err) {

Do I delete the err ?

https://jsfiddle.net/vhgL96se/90/


    button.addEventListener("click", function () {
        if (!canPlay) {
            return;
        }
        if (player.paused) {
            player.play().then(function () {
                playPauseIcon(true);
            }).catch(function (err) {
                playPauseIcon(false);
            });
        } else {
            player.pause();
            playPauseIcon(false);
        }
    });

Right. How about showing the error in the console or something? I wouldn’t delete it, you might want to be able to debug WHAT the error is.

1 Like

If the value is an incorrect stream link, the play button still changes to pause.

This is what we were preventing from happening.

https://jsfiddle.net/vhgL96se/92/

It still does this:

And that has nothing to do with the player.play().then().catch() – you set playPauseIcon(true) TWICE before you even get into the play() handler. Go through your code, and remove the extra ones that are triggering when you don’t want them to.

Hint: Take a look in your player.onloadstart handler. That bad boy is causing you problems, and there’s no logical reason for it being there.

I should delete this whole thing?

    player.onloadstart = function () {
        if (value.value !== "") {
            canPlay = true;
            playPauseIcon(true);
        }
    };

Does it actually serve a purpose? I might suggest you comment it out, and hammer on your player. If nothing changes, you can safely delete it.

What do I do next?

With this Removed:
The Play button does not change to Pause.
When audio is playing.
https://jsfiddle.net/vhgL96se/108/

  /* player.onloadstart = function () {
        if (value.value !== "") {
            canPlay = true;
            playPauseIcon(true);
        }
    };*/

With this Added:
The Play button changes to Pause.
When audio is playing.
https://jsfiddle.net/vhgL96se/106/

   player.onloadstart = function () {
        if (value.value !== "") {
            canPlay = true;
            playPauseIcon(true);
        }
    };

Ah right. So all the code you’ve been doing has been stuck in the play/pause button. That is handling the play().then().catch(). the ‘Set’ button sets the track, but doesn’t actually start anything playing. Seems to me, you’re getting this WAY more spaghetti-code than it needs to be.

Start by removing the playPauseIcon(true) from the then() handler, and uncomment your player.onloadstart thing.