Whats the best way to stop the audio from playing? - javascript

let snare = new Audio (`snare.mp3`);
let kick = new Audio (`kick.mp3`);
let hihat = new Audio (`hihat.mp3`);
let arr =[snare,kick,hihat];
let divs = document.querySelectorAll(`div`);
let body = document.querySelector(`body`);
body.addEventListener(`keydown`,(e)=>{
if(e.key ===`d`){
console.log(`ITS ${e.key}`);
e.stopPropagation();
arr[0].play()
}
if(e.key ===`f`){
console.log(`ITS ${e.key}`)
arr[1].play()
}
if(e.key ===`g`){
console.log(`ITS ${e.key}`);
arr[2].play()
}
})
div {
width:50px;
height:50px;
border:1px solid red
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="music.css" type="text/css">
</head>
<body>
<div id="d">d</div>
<div id="f">f</div>
<div id="g">g</div>
<script src="music.js"></script>
</body>
</html>
Hello, currently I'm trying to make a drum kit , where you would press the button and a different type of sound would play. But I run into a problem where if I keep pressing the same button the previous EventListener wouldnt stop playing. So my question is whats the best way to solve this problem? For example , what I want to do is keep mashing the same F button, to get the sound played repeatedly. But right now it doesnt play if the previous sound hasnt ended. Any help is appreciated :)

I rewrite your script in another way to reach your goal. Here is my script:
let audiArr = [
{
source: "snare.mp3",
buttonKey: "d"
},
{
source: "kick.mp3",
buttonKey: "f"
},
{
source: "hihat.mp3",
buttonKey: "g"
}
];
let body = document.querySelector(`body`);
let currentAudio = [];
body.addEventListener(`keydown`,(e)=>{
playSound(e.key);
});
function playSound(keyArgu) {
let keyArr;
let audioContainer;
audiArr.forEach(ele => {
keyArr = ele.buttonKey;
if (keyArr == keyArgu) {
audioContainer = new Audio (ele.source);
currentAudio.push( audioContainer );
stopPlay(currentAudio);
audioContainer.play();
}
});
}
function stopPlay(currentAudioArgu) {
let lengVar = currentAudioArgu.length;
for (let index = 0; index < lengVar -1; index++) {
currentAudioArgu[index].pause();
}
}
I first grouped each key with the corresponding sound in an array of objects, then I used playSound() function to determine if the special key was pressed at first with the help of stopPlay() function pause other sounds and then play the sound that is related to this key. The role of currentAudio array is important to reach your goal, it stores the list of last audios and by pressing new key it pauses them.

Related

Why recorded a space bar in keypress event will cause some exception

I had an issue inside my code, there it is:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function typeWriter() {
function genOutput() {
function genText() {
//generate random alphabet via ASCII char code
return String.fromCharCode(0|Math.random()*26+97);
}
const text = document.getElementById("genText");
text.textContent = genText() + text.textContent;
}
const text = document.getElementById("genText");
const score = document.getElementById("scoreBoard");
text.textContent = "";
window.setInterval(genOutput, 400); //automatically generate one charracter per 0.4 sec
document.addEventListener('keypress', (e) => {
const input = String.fromCharCode(e.charCode);
const lastCharacter = text.textContent.charAt(text.textContent.length-1);
if (input == lastCharacter) {
const newText = text.textContent.slice(0, -1);
text.textContent = newText;
score.innerText = "" + (parseInt(score.innerText)+3);
}
else if (input == " ") {
//check if user type space bar
alert("Click to continue"); //if remove this alert will occur exception
}
else {
score.innerText = "" + (parseInt(score.innerText)-1);
}
})
}
</script>
<div class="container">
<p id="title">Typewriter 2.0</p>
</div>
<div class="container">
<h1 id="genText">Typed correct +3 pt, incorrect -1 pt</h1><br>
<button id="startBtn" onclick="typeWriter()">Click to Start</button>
<span>Score: </span><span id="scoreBoard">10</span>
</div>
</body>
</html>
The simple code above is a typewriter web game, it generates an alphabet randomly every 400ms, and removes the last character if a user types correctly. However, the issue is, that when the user types the space bar, the countdown of the interval restart and generate more and more alphabet at one time. I tried to check if the user types the space bar and inserts the alert function, it can prevent the exception occur, but somehow it became a pause button. Can anyone explain to me how and why this exception happens? Thank you so much!
Your click to start button has focus after it is pressed, so spacebar will act to click the button again.
The alert caused focus to move away from the button, which is why spacebar no longer fired the event.
If you want to remove focus, you can add a blur event (on the button) to remove focus so spacebar won't function to click the button
e.target.blur();
In the event listener, e.target is the button that was clicked, so we can programmatically fire the blur event
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function typeWriter() {
function genOutput() {
function genText() {
//generate random alphabet via ASCII char code
return String.fromCharCode(0|Math.random()*26+97);
}
const text = document.getElementById("genText");
text.textContent = genText() + text.textContent;
}
const text = document.getElementById("genText");
const score = document.getElementById("scoreBoard");
text.textContent = "";
window.setInterval(genOutput, 400); //automatically generate one charracter per 0.4 sec
document.addEventListener('keypress', (e) => {
e.target.blur(); // remove focus from the button so spacebar won't continue game
const input = String.fromCharCode(e.charCode);
const lastCharacter = text.textContent.charAt(text.textContent.length-1);
if (input == lastCharacter) {
const newText = text.textContent.slice(0, -1);
text.textContent = newText;
score.innerText = "" + (parseInt(score.innerText)+3);
}
else if (input == " ") {
//check if user type space bar
// alert("Click to continue"); //if remove this alert will occur exception
}
else {
score.innerText = "" + (parseInt(score.innerText)-1);
}
})
}
</script>
<div class="container">
<p id="title">Typewriter 2.0</p>
</div>
<div class="container">
<h1 id="genText">Typed correct +3 pt, incorrect -1 pt</h1><br>
<button id="startBtn" onclick="typeWriter()">Click to Start</button>
<span>Score: </span><span id="scoreBoard">10</span>
</div>
</body>
</html>

{button}.onclick to change textContent

I'm trying make simple game "Rock Paper Scissors". At this moment I got stuck in changing value of Global Variable. Situation: (for ex.) Click => [Rock]. I have to store this into Global Variable's ("playerMove").
const rock = document.createElement('button');
/*
*/
let playerMove;
playerMove = '';
I arleady try
rock.onclick = function() {
playerMove = 'Rock'; // Test in function..
}
but Its only work in function (Yea, we all know global variable doesn't work that way so..). I may be able to fix that problem soon but at this moment my mind can't think any better than this :|, I want help to find any good resource about this to (how) change textContent / Value of element by clicking on button.
Sorry for my bad English..
You can use HTMLButtonElement.addEventListener() to listen for "click" events, and then do whatever you want to, a simple demo
const btn = document.getElementById('test');
const container = document.getElementById('val');
btn.addEventListener('click', () => {
container.textContent = 'works'
})
<div id="val">test</div>
<button id="test">click me</button>
To update the playerMove variable you could use a function that set that value.
document.createElement('button');
const rock = document.querySelector('button');
let playerMove = ''
const updateMove = (move) => {
playerMove = move;
}
rock.onclick = () => {
updateMove('Rock');
}
const rock = document.getElementById('button');
console.log(rock)
let playerMove;
playerMove = '';
rock.addEventListener('click',(e)=>{
playerMove =e.target.innerHTML;
console.log(playerMove);
})
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title> Aide</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<header>
<button id="button">Rock</button>
<script type="text/javascript" src="index.js"></script>
</body>
</html>
strong text
This code works perfectly.
it takes the text that the button contains.
I think your mistake is that you didn't declare that the button you created a js is a child of body.
Ty guys
Well, I will explain lil more about what playerMove was doing..
playerText.textContent = playerMove;
so I simple was trying to change playerMove but after I see AnanthDev answer >>
function playerMove(element, move) {
element.addEventListener('click', () => {
playerText.textContent = move;
})
}
playerMove(rock, 'Rock');
playerMove(scissors, 'Scissors');
playerMove(paper, 'Paper');

How can I get the next and previous buttons working on my javascript code

I'm a new programmer learning and working on an image gallery with a full-screen popup using vanilla javascript and the console keep saying: Cannot set property 'src' of undefined at nextPic (app.js:35) at HTMLAnchorElement.onclick (Imagegallery.html:18).
The HTML code. I have the script running at the end. I am wondering if I need to remove the last popup event listener?? So the user can just keep clicking through using the next and previous buttons. Then, I would like for it once the user gets to the end of the gallery it automatically returns back or could press and X put to exit. I hope this helps to get my problem figured out.
const popup = document.getElementById('popup'); //reference to popup
const selectedImage = document.getElementById('selectedImage'); //reference to selected image
const imageIndexes = [1,2,3]; //array of images
const selectedIndex = null;
var currPic = 0;
var pics= '';
//to show image gallery
imageIndexes.forEach((i)=>{
const image = document.createElement('img'); //reference to image
image.src=`images/logo${i}.PNG`; //updated the source with number dynamically
image.classList.add('galleryImg'); // adding a css class
image.addEventListener('click',() =>{
//popup stuff
popup.style.transform =`translateY(0)`; //image slide down when clicked
selectedImage.src=`images/logo${i}.PNG`;
})
gallery.appendChild(image);
});
function nextPic(e){
e.preventDefault();
if (currPic < imageIndexes.length -1){
currPic++;
document.getElementById('prev').style.display = 'block';
}
else {
document.getElementById('next').style.display = 'none';
document.getElementById('prev').style.display = 'block';
}
document.popup.src = imageIndexes[currPic];
}
function prevPic(e){
e.preventDefault();
if (currPic > 0){
currPic--;
document.getElementById('next').style.display = 'block';
}
else {
document.getElementById('prev').style.display = 'none';
}
document.popup.src = imageIndexes[currPic];
}
popup.addEventListener('click', ()=>{
popup.style.transform =`translateY(-100%)`; //image slides back up
popup.src ='';
});```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Gallery</title>
<link rel="stylesheet" href="image.css">
</head>
<body>
<div class="container">
<h1>Image Gallery</h1>
<div id="gallery"></div>
</div>
<div id="popup">
<img src="" alt="" id="selectedImage">
Prev Next
</div>
<script src="app.js"></script>
</body>
</html>

How to make a function that creates toggle buttons for a setTimeout loop?

I am trying to create a function that lets me create an on/off toggle button for setTimeout loops and I am having difficulty figuring out how to get this to work the way I want it. The only way I was able to get the loop to stop was by declaring a variable in the global scope that stores the Id value for the setTimeout loop but which defeats the purpose. This also causes an issue if I try to create a second toggle button for a different loop as all the buttons access the same variable. Help would be appreciated. Thank you
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="mainContainer">
<h1 id='pointA'>Point A</h1>
<p id='pointB'>Point B</p>
</div>
</body>
<script>
function createCustomToolbar(){
var myToolbarCustom = document.createElement('div');
var targetPage= document.querySelector('body');
var myCSS=myToolbarCustom.style;
myToolbarCustom.id='myToolbarCustom';
targetPage.append(myToolbarCustom);
targetPage.style.padding='transform 0.4s ease';
targetPage.style.padding='40px';
myCSS.position='fixed';
myCSS.top=0;
myCSS.left=0;
myCSS.width='100%';
myCSS.height='35px';
myCSS.border=0;
myCSS.background='#e3e3e3'
myCSS.zIndex=9999999;
}
var x;
function toggleCreator(bttnName,callback,targetEle){
var state=false;
var mybttn=document.createElement('button');
mybttn.className='myCustomTog';
mybttn.innerHTML=bttnName;
var bttnTarget=document.getElementById('myToolbarCustom');
bttnTarget.appendChild(mybttn)
mybttn.onclick = function() {
state = !state;
if (state) {
mybttn.innerHTML = bttnName + " ON";
x = callback(targetEle);
} else {
mybttn.innerHTML = bttnName + " OFF";
clearTimeout(x);
}}
}
createCustomToolbar();
toggleCreator("start",testToggle,document.getElementById('pointA'));
toggleCreator("start",testToggle,document.getElementById('pointB'));
var i=0;
function testToggle(myTarget){
x= setTimeout(function(){
myTarget.innerHTML=i;
i++;
testToggle(myTarget);
},1000)
}
</script>
</html>
You're going to have multiple buttons and multiple timeOuts (one for each).
I'd create an empty array to store the timeOuts and use x as an index for this array.
var x = 0;
var timeouts_arr = [];
Inside testToggle...
x++;
myTarget.setAttribute('timeout_index', x);
timeouts_arr[x] = setTimeout(function(){...
inside mybttn.onclick...
state = !state;
if (state) {
mybttn.innerHTML = bttnName + " ON";
callback(targetEle); // don't use the x variable here
} else {
mybttn.innerHTML = bttnName + " OFF";
var timeout_index = mybttn.getAttribute('timeout_index');
clearTimeout(timeout_arr[timeout_index]);
}}

Pause song on next click, Javascript

I have 5 div boxes that play a certain track on click (using data attributes), however, I can't seem to figure out how to pause the previous track on next click. The audio plays on top of each other.
Javascript:
var audio = ['song-1.mp3','song-2.mp3','song-3.mp3','song-4.mp3','song-
5.mp3'];
var music = document.querySelector('#container');
music.addEventListener('click', function(evt){
if(evt.target.tagName === "DIV"){
var index = evt.target.getAttribute('data-index');
var sound = new Audio(audio[index]);
sound.play();
audio.forEach(function(x){
if(x !== sound){
sound.pause();
}
})
}
});
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="style.css"/>
</head>
<body>
<section id="container">
<div data-index="0"><p>40's</p></div>
<div data-index="1"><p>50's</p></div>
<div data-index="2"><p>60's</p></div>
<div data-index="3"><p>70's</p></div>
<div data-index="4"><p>80's</p></div>
<div data-index="5"><p>90's</p></div>
<div data-index="6"><p>2000's</p></div>
<div data-index="7"><p>2010's</p></div>
</section>
<script src='script.js'></script>
</body>
</html>
sound will always refers to the most recently clicked sound, never to the one that was playing before. The easiest solution is probably to keep a variable playing that tracks the audio object that is currently playing. That way when a new sound is played, you have a reference to the old one that you can pause. That could look something like this
var audio = ['song-1.mp3','song-2.mp3','song-3.mp3','song-4.mp3','song-
5.mp3'];
var music = document.querySelector('#container');
var playing = undefined;
music.addEventListener('click', function(evt){
if(evt.target.tagName === "DIV"){
var index = evt.target.getAttribute('data-index');
var sound = new Audio(audio[index]);
if (playing) playing.pause();
sound.play();
playing = sound;
}
});
Another option is for you to just keep an array of audio objects and track the index of the currently playing audio. That could look like this. This may be preferable because it will keep the place of paused songs.
var audioNames = ['song-1.mp3','song-2.mp3','song-3.mp3','song-4.mp3','song-
5.mp3'];
var audio = [];
for (var a in audioNames) {
audio.push(new Audio(a));
}
var music = document.querySelector('#container');
var playingIndex = undefined;
music.addEventListener('click', function(evt){
if(evt.target.tagName === "DIV"){
var index = evt.target.getAttribute('data-index');
var sound = audio[index];
if (playing) audio[playingIndex].pause();
sound.play();
playingIndex = index;
}
});

Categories

Resources