I am building a music player using HTML-css-javascript only. I have a list of music which I have stored in an array as shown below.
let songs = [
{songName: "Butter", filePath:"songs/1.mp3",coverPath:'covers/1.png'},
{songName: "Boy With Luv", filePath:"songs/2.mp3",coverPath:'covers/2.jpeg'},
{songName: "Dynamite", filePath:"songs/3.mp3",coverPath:'covers/3.jpeg'},
{songName: "Idol", filePath:"songs/4.mp3",coverPath:'covers/4.png'},
{songName: "Life Goes On", filePath:"songs/5.mp3",coverPath:'covers/5.jpeg'},
{songName: "Mic Drop", filePath:"songs/6.mp3",coverPath:'covers/6.jpeg'},
]
And the UI looks like this:
Things look good that on clicking specific songs, the play icon on the side of the song name changes, but when I change the song with the next button at the bottom, the song changes but the icon still remains unchanged. As you can see in the second image, I changed to the fourth song but the music list still shows the third song playing.
I need to change the styling of the icon with the click of the next&previous button at the bottom. I have songindex of the current song playing in the function.
for reference attached the nextButton code:
//next button
document.getElementById('next').addEventListener('click', (e)=>{
songIndex = (songIndex >=5) ? 0 : songIndex+1;
audioElement.src = `songs/${songIndex}.mp3`;
audioElement.currentTime = 0;
audioElement.play();
masterPlay.classList.remove('fa-play-circle');
masterPlay.classList.add('fa-pause-circle');
mastersongName.innerText = "BTS - "+songs[songIndex].songName;
masterSideImg.src = songs[songIndex].coverPath;
})
COmplete HTML code:
<!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>Redify - listen music here</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<nav>
<ul>
<li class="brand"><img src="logo.png" alt="logo">Spotify</li>
<li>Home</li>
<li>About</li>
</ul>
</nav>
<div class="container">
<div class="songList">
<h1>Best of BTS</h1>
<div class="songitemContainer">
<div class="songItem">
<img alt="1">
<span class="songName">Butter</span>
<span class="songlistPlay">
<span class="timestamp">3:41
<i id="0" class="far songItemPlay fa-1.5x fa-play-circle"></i>
</span>
</span>
</div>
<div class="songItem">
<img alt="1">
<span class="songName">Butter</span>
<span class="songlistPlay">
<span class="timestamp">3:41
<i id="1" class="far songItemPlay fa-1.5x fa-play-circle"></i>
</span>
</span>
</div>
<div class="songItem">
<img alt="1">
<span class="songName">Butter</span>
<span class="songlistPlay">
<span class="timestamp">3:41
<i id="2" class="far songItemPlay fa-1.5x fa-play-circle"></i>
</span>
</span>
</div>
<div class="songItem">
<img alt="1">
<span class="songName">Butter</span>
<span class="songlistPlay">
<span class="timestamp">3:41
<i id="3" class="far songItemPlay fa-1.5x fa-play-circle"></i>
</span>
</span>
</div>
<div class="songItem">
<img alt="1">
<span class="songName">Butter</span>
<span class="songlistPlay">
<span class="timestamp">3:41
<i id="4" class="far songItemPlay fa-1.5x fa-play-circle"></i>
</span>
</span>
</div>
<div class="songItem">
<img alt="1">
<span class="songName">Butter</span>
<span class="songlistPlay">
<span class="timestamp">3:41
<i id="5" class="far songItemPlay fa-1.5x fa-play-circle"></i>
</span>
</span>
</div>
</div>
</div>
<div class="songBanner">
</div>
</div>
<div class="bottom">
<img src="covers/1.png" alt="side_img" width="60px" id="masterSideImg">
<div class="bottomprogress">
<input type="range" name="range" id="myProgressBar" min="0" max="100" value=0>
<div class="icons">
<i class="fas fa-2x fa-step-backward" id="previous"></i>
<i class="far fa-2x fa-play-circle" id="masterPlay"></i>
<i class="fas fa-2x fa-step-forward" id="next"></i>
</div>
<div class="songInfo">
<img src="playing.gif" width="32px" alt="playing" id="gif"><span id="mastersongName">BTS - Butter</span>
</div>
</div>
</div>
<script src="https://kit.fontawesome.com/06646b7200.js" crossorigin="anonymous"></script>
<script src="script.js"></script>
The complete link of the project is given here: https://github.com/mohitm15/Redify
I refactored your play/pause icon setting part into a function:
const ICON_PLAY = 1;
const ICON_STOP = 0;
const handleSongPlayIcon = (target, isPlaying) => {
if (isPlaying == ICON_PLAY) {
target.classList.remove("fa-pause-circle");
target.classList.add("fa-play-circle");
} else if (isPlaying == ICON_STOP) {
target.classList.remove("fa-play-circle");
target.classList.add("fa-pause-circle");
}
};
and adjusted several functions in your code, toggling the icons
//Variable initialisation
let songIndex = 0;
let audioElement = new Audio("songs/0.mp3");
let masterPlay = document.getElementById("masterPlay");
let myProgressBar = document.getElementById("myProgressBar");
let gif = document.getElementById("gif");
let songItems = Array.from(document.getElementsByClassName("songItem"));
let songTitle = document.getElementsByClassName("songInfo");
let mastersongName = document.getElementById("mastersongName");
let masterSideImg = document.getElementById("masterSideImg");
//console.log(songTitle.innerText)
let songs = [
{ songName: "Butter", filePath: "songs/1.mp3", coverPath: "covers/1.png" },
{
songName: "Boy With Luv",
filePath: "songs/2.mp3",
coverPath: "covers/2.jpeg",
},
{ songName: "Dynamite", filePath: "songs/3.mp3", coverPath: "covers/3.jpeg" },
{ songName: "Idol", filePath: "songs/4.mp3", coverPath: "covers/4.png" },
{
songName: "Life Goes On",
filePath: "songs/5.mp3",
coverPath: "covers/5.jpeg",
},
{ songName: "Mic Drop", filePath: "songs/6.mp3", coverPath: "covers/6.jpeg" },
];
const ICON_PLAY = 1;
const ICON_STOP = 0;
const handleSongPlayIcon = (target, isPlaying) => {
if (isPlaying == ICON_PLAY) {
target.classList.remove("fa-pause-circle");
target.classList.add("fa-play-circle");
} else if (isPlaying == ICON_STOP) {
target.classList.remove("fa-play-circle");
target.classList.add("fa-pause-circle");
}
};
songItems.forEach((item, i) => {
//console.log(item, i);
item.getElementsByTagName("img")[0].src = songs[i].coverPath;
item.getElementsByClassName("songName")[0].innerText = songs[i].songName;
//item.getElementsByClassName("timestamp")[0].innerText = parseInt(audioElement.duration*1);
});
//audioElement.play();
//handle play/pause
masterPlay.addEventListener("click", () => {
// grab all the icon elements on the page
const allSongsPlayItemElements = document.querySelectorAll(".songItemPlay");
if (audioElement.paused || audioElement.currentTime <= 0) {
audioElement.play();
handleSongPlayIcon(masterPlay, ICON_STOP);
handleSongPlayIcon(allSongsPlayItemElements[songIndex], ICON_STOP);
gif.style.opacity = 1;
} else {
audioElement.pause();
handleSongPlayIcon(masterPlay, ICON_PLAY);
handleSongPlayIcon(allSongsPlayItemElements[songIndex], ICON_PLAY);
gif.style.opacity = 0;
}
});
//Listen to event
audioElement.addEventListener("timeupdate", () => {
//update songbar
progress = parseInt((audioElement.currentTime / audioElement.duration) * 100);
myProgressBar.value = progress;
});
myProgressBar.addEventListener("change", () => {
audioElement.currentTime =
(myProgressBar.value * audioElement.duration) / 100;
});
//songlist appear on landing page
//makes button of all songs to display play symbol
const makeAllPlay = () => {
Array.from(document.getElementsByClassName("songItemPlay")).forEach(
(item) => {
handleSongPlayIcon(item, ICON_PLAY);
}
);
};
//songList :eventListener for song playing/pausing
let selectedSongIndex;
Array.from(document.getElementsByClassName("songItemPlay")).forEach((item) => {
item.addEventListener("click", (e) => {
//console.log(e.target) gives => <i class="far songItemPlay fa-1.5x fa-pause-circle" aria-hidden="true"></i>
makeAllPlay();
songIndex = parseInt(e.target.id);
//songIndex = the song is playing currently (for first time)
//selectedsongIndex = the song that user clicked when any song is playing (after first time)
if (audioElement.paused === true) {
selectedSongIndex = songIndex;
audioElement.src = `songs/${songIndex}.mp3`;
audioElement.currentTime = 0;
audioElement.play();
//console.log("song is playing" );
handleSongPlayIcon(e.target, ICON_STOP);
handleSongPlayIcon(masterPlay, ICON_STOP);
gif.style.opacity = 1;
} else if (audioElement.paused === false) {
if (selectedSongIndex === songIndex) {
audioElement.pause();
//console.log("audio is paused now")
handleSongPlayIcon(e.target, ICON_PLAY);
handleSongPlayIcon(masterPlay, ICON_PLAY);
gif.style.opacity = 0;
} else {
makeAllPlay();
songIndex = parseInt(e.target.id);
selectedSongIndex = songIndex;
audioElement.src = `songs/${songIndex}.mp3`;
audioElement.currentTime = 0;
audioElement.play();
//console.log("song is playing" );
handleSongPlayIcon(e.target, ICON_STOP);
handleSongPlayIcon(masterPlay, ICON_STOP);
gif.style.opacity = 1;
}
}
//console.log("songIndexx = ",songIndex);
//console.log("selected = " +selectedSongIndex);
mastersongName.innerText = "BTS - " + songs[songIndex].songName;
masterSideImg.src = songs[songIndex].coverPath;
audioElement.addEventListener("timeupdate", () => {
// console.log("songcurrentTime = "+parseInt(audioElement.currentTime))
// console.log("song duartion = "+ parseInt(audioElement.duration));
if (audioElement.currentTime === audioElement.duration) {
makeAllPlay();
console.log("song Completed");
songIndex = songIndex >= 5 ? 0 : songIndex + 1;
audioElement.src = `songs/${songIndex}.mp3`;
audioElement.currentTime = 0;
audioElement.play();
mastersongName.innerText = "BTS - " + songs[songIndex].songName;
masterSideImg.src = songs[songIndex].coverPath;
// grab all the icon elements on the page
const allSongsPlayItemElements = document.querySelectorAll(".songItemPlay");
handleSongPlayIcon(allSongsPlayItemElements[songIndex], ICON_STOP);
//previous can be accessed with e.target.id
//how to access the next element (as it is not being clicked by user)
}
});
});
});
//next button
document.getElementById("next").addEventListener("click", (e) => {
// grab all the icon elements on the page
const allSongsPlayItemElements = document.querySelectorAll(".songItemPlay");
// set the currently playing icon to "play"
handleSongPlayIcon(allSongsPlayItemElements[songIndex], ICON_PLAY);
songIndex = songIndex >= 5 ? 0 : songIndex + 1;
audioElement.src = `songs/${songIndex}.mp3`;
audioElement.currentTime = 0;
audioElement.play();
handleSongPlayIcon(masterPlay, ICON_STOP);
mastersongName.innerText = "BTS - " + songs[songIndex].songName;
masterSideImg.src = songs[songIndex].coverPath;
// set the next song icon to "stop"
handleSongPlayIcon(allSongsPlayItemElements[songIndex], ICON_STOP);
});
//previous button
document.getElementById("previous").addEventListener("click", (e) => {
// grab all the icon elements on the page
const allSongsPlayItemElements = document.querySelectorAll(".songItemPlay");
// set the currently playing icon to "play"
handleSongPlayIcon(allSongsPlayItemElements[songIndex], ICON_PLAY);
songIndex = songIndex <= 0 ? 5 : songIndex - 1;
audioElement.src = `songs/${songIndex}.mp3`;
audioElement.currentTime = 0;
audioElement.play();
handleSongPlayIcon(masterPlay, ICON_STOP);
mastersongName.innerText = "BTS - " + songs[songIndex].songName;
masterSideImg.src = songs[songIndex].coverPath;
// set the next song icon to "stop"
handleSongPlayIcon(allSongsPlayItemElements[songIndex], ICON_STOP);
});
Looks to me like you forgot to call makeAllPlay(); at the beginning of the previous/next button click handlers. Also you'll want to change the newly playing song item to show the pause button.
Near the beginning of the two click handlers (for previous/next buttons) add:
makeAllPlay();
const itemElem = document.getElementsByClassName("songItemPlay")[songIndex];
itemElem.classList.remove('fa-play-circle');
itemElem.classList.add('fa-pause-circle');
Related
The below is part of a media player. Unfortunately, I cannot find the reason why the event listener is not registering the clicks on the hearts (when a user favorites a song). I have tried several implementations and I am researching for the last week with no success. Can you help?
How can I make the click listener to update the heart count?
HTML
<div class="player">
<div class="dashboard">
<header>
<p>Playing:</p>
</header>
<div class="cd">
<div class="cd-thumb">
</div>
</div>
<div class="control">
<div class="btn btn-random inactive">
<i class="fas fa-random"></i>
</div>
<div class="btn btn-prev">
<i class="fas fa-step-backward"></i>
</div>
<div class="btn btn-toggle-play">
<i class="fas fa-pause icon-pause"></i>
<i class="fas fa-play icon-play"></i>
</div>
<div class="btn btn-next">
<i class="fas fa-step-forward"></i>
</div>
<div class="btn btn-mute-unmute inactive">
<i class="fas fa-volume-up"></i>
</div>
</div>
</div>
<div class="playlist">
</div>
Script 1
render: function () {
let that = this;
fetch("hearts.txt")
.then(function(response) {
return response.json();
})
.then(function(heartCounts) {
let t = that.songs.map(
(t, e) => `
<div class="song ${
e === that.currentIndex ? "active" : ""
}" data-index="${e}">
<div class="thumb"
style="background-image: url('${t.image}')">
</div>
<div class="body">
<h3 class="title">${t.name}</h3>
<p class="author">${t.singer}</p>
</div>
<div class="heart" data-song-id="${e}">
<i class="fa fa-heart${
heartCounts[e] ? " active" : ""
}"></i> <span>${heartCounts[e] || 0}</span>
</div>
</div>
`
);
playlist.innerHTML = t.join("");
});
},
Script 2
const getHeartCounts = function () {
let xhr = new XMLHttpRequest();
xhr.open("GET", "return.php", true);
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
let heartCounts = JSON.parse(xhr.responseText);
// Update the heart count displays
document.querySelectorAll(".heart i + span").forEach((countDisplay, i) => {
countDisplay.innerHTML = heartCounts[i];
});
// Update the active heart icons
document.querySelectorAll(".heart i").forEach((heart, i) => {
if (heartCounts[i] > 0) {
heart.classList.add("active");
}
});
}
};
xhr.send();
};
document.addEventListener("DOMContentLoaded", function () {
// Add click listener to update the heart count
document.querySelectorAll(".heart").forEach(function (heart) {
heart.addEventListener("click", function (e) {
let target = e.target,
songIndex = parseInt(target.dataset.songId),
countEl = target.querySelector("span"),
heartCount = countEl ? parseInt(countEl.innerHTML) : 0,
isActive = target.classList.contains("active");
// Update the heart count
heartCount = isActive ? heartCount - 1 : heartCount + 1;
if (countEl) {
countEl.innerHTML = heartCount;
}
let heartIcon = target.querySelector("i");
if (heartIcon) {
heartIcon.classList.toggle("active", !isActive);
}
// Update the heart count on the server
let xhr = new XMLHttpRequest();
xhr.open("POST", "store.php", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("index=" + songIndex + "&count=" + heartCount);
});
});
// Update the heart counts on page load
getHeartCounts();
});
I want to make my own To Do list using JavaScript and localStorage. After writing the input and pressing the send button, the item will be added and display on the screen. A check button will appear next to the item. After pressing the check button, I want the class to be added. I want add css (opacity, line...). But when I press a check button, the console shows this error: Uncaught TypeError: Cannot read properties of undefined (reading 'add')
at check (app.js:23)
at HTMLElement.onclick (index.html:30)
HTML code:
<body>
<div class="main">
<input id="item" type="text">
<i id="addItem" class="fas fa-plus"></i><br> <br>
</div>
<div class="items">
<div id="addedItems"></div>
</div>
<i onclick='deleteAll()' class="fas fa-trash"></i>
</body>
JS code:
const item = document.getElementById("item");
const add = document.getElementById("addItem");
const addedItems = document.getElementById("addedItems");
add.onclick = function() {
const itemValue = item.value;
const itemValue2 = ' ';
if (itemValue && itemValue2) {
localStorage.setItem(itemValue, itemValue2);
location.reload();
}
};
for (let a = 0; a < localStorage.length; a++) {
const itemValue = localStorage.key(a);
addedItems.innerHTML += `<div class= 'text'> <div>${itemValue}</div> <div>
<i onclick='check("${itemValue}")' class="fas fa-check"></i><i
onclick='deleteItem("${itemValue}")' class="fas fa-trash-alt"></i>
</div></div> <br>`;
}
function check(itemValue) {
itemValue.classList.add("mystyle");
}
function deleteItem(itemValue) {
localStorage.removeItem(itemValue);
location.reload();
}
function deleteAll() {
localStorage.clear();
location.reload();
}
You can try this answer:
<script>
const item = document.getElementById("item");
const add = document.getElementById("addItem");
const addedItems = document.getElementById("addedItems");
add.onclick = function() {
const itemValue = item.value;
const itemValue2 = ' ';
if (itemValue && itemValue2) {
localStorage.setItem(itemValue, itemValue2);
location.reload();
}
};
for (let a = 0; a < localStorage.length; a++) {
const itemValue = localStorage.key(a);
addedItems.innerHTML += `<div class= 'text'> <div>${itemValue}</div> <div>
<i onclick='check("${itemValue}", ${a})' class="fas fa-check" id="${a}"></i><i
onclick='deleteItem("${itemValue}")' class="fas fa-trash-alt"></i>
</div></div> <br>`;
}
function check(itemValue, id) {
const elem = document.getElementById(id);
elem.classList.add("mystyle");
}
function deleteItem(itemValue) {
localStorage.removeItem(itemValue);
location.reload();
}
function deleteAll() {
localStorage.clear();
location.reload();
}
</script>
<div class="main">
<input id="item" type="text">
<i id="addItem" class="fas fa-plus"></i><br> <br>
</div>
<div class="items">
<div id="addedItems"></div>
</div>
<i onclick='deleteAll()' class="fas fa-trash"></i>
Only changes I made is pass id of element for checkbox click along with itemValue element. Value you are passing checkbox value not document element. If you console you will get to know itemValue is just string not DOM element.
Here is fiddle : https://jsfiddle.net/aviboy2006/ortqu1ps/
Index.html
I'm trying to read data from object but i found that it is not working properly . seekbar also giving null error . The images and song is stored locally and i'm trying to access that.
<div class="music-player">
<div class="song">
<div class="current-song-image"></div>
<div class="current-song-name"><Song Name></div>
<div class="current-song-artist">Song Artist Name</div>
</div>
<!-- song playing bar -->
<div class="song-seek-line">
<div class="curr-time">00:00</div>
<input
type="range"
min="1"
max="100"
value="0"
class="seek-bar"
onchange="jumpTo()"
/>
<div class="end-time">00:00</div>
</div>
<!-- volume control bar -->
<div class="volume-control">
<i class="fa fa-volume-down volume-down"></i>
<input
type="range"
min="1"
max="100"
value="99"
class="volume-bar"
onchange="volume()"
/>
<i class="fa fa-volume-up volume-up"></i>
</div>
<!-- song control buttons -->
<div class="playing-buttons">
<div class="prev-song-button" onclick="prevSong()">
<i class="fa fa-step-backward fa-2x"></i>
</div>
<div class="song-play-pause-button" onclick="PlayPauseSong()">
<i class="fa fa-play-circle fa-5x"></i>
</div>
<div class="next-song-button" onclick="nextSong()">
<i class="fa fa-step-forward fa-2x"></i>
</div>
</div>
</div>
Index.js
let song_num = 0;
let currentlySongPlaying = false;
let changeTimer;
let songlist = [
{
name: "Khaab",
artist:"Akhil",
image: 'images/khaab_song_image.jpg',
songPath: "songs/khaab.mp3"
},
];
// console.log(songlist[2]); // object created successfully
function loadSong(song_num){
clearInterval(changeTimer);
resetValues();
document.createElement('audio').src = songlist[song_num].songPath;
document.createElement('audio').load();
console.log(songlist[song_num].image);
console.log(songlist[song_num].name);
console.log(songlist[song_num].artist);
document.querySelector('.current-song-image').style.backgoundImage = "url(" + songlist[song_num].image + ")";
document.querySelector('.current-song-name').textContent = songlist[song_num].name;
document.querySelector('.current-song-artist').textContent = songlist[song_num].artist;
changeTimer = setInterval(seekUpdatedTime,1000);
document.createElement('audio').addEventListener("songFinished",nextSong);
}
function resetValues(){
document.querySelector('.curr-time').textContent = "00:00";
document.querySelector('.end-time').textContent = "00:00";
document.querySelector('.seek-bar').value = 0;
}
function PlayPauseSong(){
if(!currentlySongPlaying) playSong();
else pauseSong();
}
function playSong(){
document.createElement('audio').play();
currentlySongPlaying = true;
document.querySelector('.song-play-pause-button').innerHTML = '<i class="fa fa-pause-circle fa-5x"></i>';
}
function pauseSong(){
document.createElement('audio').pause();
currentlySongPlaying = false;
document.querySelector('.song-play-pause-button').innerHTML = '<i class="fa fa-play-circle fa-5x"></i>';
}
function nextSong(){
if(song_num<songlist.length-1){
song_num+=1;
}else{
song_num=0;
}
loadSong(song_num);
playSong();
}
function prevSong(){
if(song_num>0){
song_num-=1;
}else{
song_num = songlist.length-1;
}
loadSong(song_num);
playSong();
}
function jumpTo(){
jumpto = document.createElement('audio').duration * (document.querySelector('.seek-bar').value / 100);
document.createElement('audio').currentTime = jumpto;
}
function volume(){
document.createElement('audio').volume = document.querySelector('.volume-bar').value/100;
}
function seekUpdatedTime(){
let seekPosition = 0;
if(!isNaN(document.createElement('audio').duration)){
seekPosition = document.createElement('audio').currentTime*(100/document.createElement('audio').duration);
document.querySelector('.seek-bar').value = seekPosition;
let currentSongMinLeft = Math.floor(document.createElement('audio').currentTime/60);
let currentSongSecLeft = Math.floor(document.createElement('audio').currentTime - currentSongMinLeft * 60);
let SongDurationMin = Math.floor(document.createElement('audio').duration/60);
let SongDurationSec = Math.floor(document.createElement('audio').duration - SongDurationMin * 60);
if(currentSongMinLeft<10)
currentSongMinLeft = "0"+currentSongMinLeft;
if(currentSongSecLeft<10)
currentSongSecLeft = "0"+currentSongSecLeft;
if(SongDurationMin<10)
SongDurationMin = "0"+SongDurationMin;
if(SongDurationSec<10)
SongDurationSec = "0"+SongDurationSec;
currSongTime.textContent = currentSongMinLeft+":"+currentSongSecLeft;
currSongEndTime.textContent = SongDurationMin+":"+SongDurationSec;
}
}
loadSong(song_num);
I'm getting errors like uncaught typeerror queryselector is null in index.js in resetValues() function .
I tried every possible thing..but not getting it. can anyone help .
Try running your code in onload event:
window.onload = function()
loadSong(song_num);
};
or put your code at the end of <body> to ensure it runs after elements are created.
Question
I have created a cart, where you can add or remove items. If you remove an item, the price is taken away from the total price calculation: and more importantly the element that is displayed as a cart item is removed from the Cart.
When many cart items are added to the cart, for some reason only the very first cart item can be removed. All subsequent remove buttons do not work.
I will do my best to provide a minimal sample:
if(document.readyState == 'loading'){
document.addEventListener('DOMContentLoaded', ready);
} else {
ready();
}
const BasketTotal = document.getElementsByClassName('basket-total')[0];
function ready(){
let removeCartItemButtons = document.getElementsByClassName('remove-btn');
for(let i = 0; i < removeCartItemButtons.length; i++){
let button = removeCartItemButtons[i];
button.addEventListener('click', removeCartItem);
}
let addToCartButtons = document.getElementsByClassName('add-to-cart-btn');
for(let i=0; i < addToCartButtons.length; i++){
let button = addToCartButtons[i];
button.addEventListener('click', addToCartClicked);
}
document.getElementsByClassName('btn-purchase')[0].addEventListener('click', purchaseClicked);
}
function purchaseClicked(){
alert('Thank you for your purchase');
var cartItems = document.getElementsByClassName('cart-cards')[0];
while(cartItems.hasChildNodes()){
cartItems.removeChild(cartItems.firstChild)
}
updateCartTotal()
}
function removeCartItem(event){
let buttonClicked = event.target;
buttonClicked.parentElement.parentElement.remove();
updateCartTotal();
}
function addToCartClicked(event){
let button = event.target;
let cartItem = button.parentElement;
let title = cartItem.getElementsByClassName('dom-title')[0].innerText;
let price = cartItem.getElementsByClassName('item-price')[0].innerText;
addItemToCart(title, price);
updateCartTotal();
}
function addItemToCart(title, price){
let basketItem = document.createElement('div');
//CartItems was changed to cartCards
let cartCards = document.getElementsByClassName('cart-cards')[0];
let cartItemNames = cartCards.getElementsByClassName('cart-domain');
for(let i = 0; i < cartItemNames.length; i++){
if(cartItemNames[i].innerText == title){
alert('This item is already added to the cart');
return;
}
}
let cartContents = `
<br>
<br>
<div class="cart-card">
<h5 class="cart-domain">${title}<span style="color: gray">.crypto</span></h5>
<hr style="width: 80%; margin: auto;">
<p class="cart-text">No recurring fees. This domain will never expire. You will own the domain outright.</p>
<br>
<br>
<button class="cart-purchase">Buy it now</button>
<div class="price-cart-item">
<br>
<br>
<p>
Price: <span class="cart-item-price">${price}</span>
</p>
<br>
<button class="remove-btn">Remove <i class="fas fa-trash"></i></button>
</div>
<p class="cart-text">Renewal Cost: $0.00</p>
</div>`;
basketItem.innerHTML = cartContents;
cartCards.append(basketItem);
cartCards.getElementsByClassName('remove-btn')[0].addEventListener('click', removeCartItem);
}
function updateCartTotal(){
let cartItemContainer = document.getElementsByClassName('cart-cards')[0];
let cartCards = cartItemContainer.getElementsByClassName('cart-card');
let total = 0;
for(let i =0; i < cartCards.length; i++){
let cartCard = cartCards[i];
let priceElement = cartCard.getElementsByClassName('cart-item-price')[0];
let price = parseFloat(priceElement.innerText.replace('$', '').replace(',', ''));
total += price;
}
total = Math.round(total * 100) / 100;
let commasAdded = total.toLocaleString();
document.getElementsByClassName('basket-total')[0].innerText = '$' + commasAdded;
}
<!--Products for sale -->
<div class="domain-item">
<p class="domain-aspect domain-title"><strong class="linked"><span class="dom-title">happy</span><span style="color: #1a6db7">.com</span></strong> <span class="item-price">$100,000</span></p>
<button class="domain-aspect add-to-cart-btn">Add To Cart</button>
</div>
<div class="domain-item">
<p class="domain-aspect domain-title"><strong class="linked"><span class="dom-title">exchange</span><span style="color: #1a6db7">.com</span></span></strong> <span class="item-price">$100,000</span></p>
<button class="domain-aspect add-to-cart-btn">Add To Cart</button>
</div>
<div class="domain-item">
<p class="domain-aspect domain-title"><strong class="linked"><span class="dom-title">bestdadever</span><span style="color: #1a6db7">.com</span></span></strong> <span class="item-price">$100,000</span></p>
<button class="domain-aspect add-to-cart-btn">Add To Cart</button>
</div>
<!--Cart-->
<div class="cart-total-text">
<p>Your Items</p>
<p>Total: <span class="basket-total"></span></p>
</div>
<div class="cart-cards">
</div>
This would really help me out if you can identify why the remove buttons are only working some of the time!
You call the ready() function only once when the document is ready. I made a little change in your code and put the ready() function into your addToCartClicked(event) function too. So every time you click the add to cart button, you create the remove buttons, and then you add the event listeners.
Hope it helps you.
if(document.readyState == 'loading'){
document.addEventListener('DOMContentLoaded', ready);
} else {
ready();
}
const BasketTotal = document.getElementsByClassName('basket-total')[0];
function ready(){
let removeCartItemButtons = document.getElementsByClassName('remove-btn');
for(let i = 0; i < removeCartItemButtons.length; i++){
let button = removeCartItemButtons[i];
button.addEventListener('click', removeCartItem);
}
let addToCartButtons = document.getElementsByClassName('add-to-cart-btn');
for(let i=0; i < addToCartButtons.length; i++){
let button = addToCartButtons[i];
button.addEventListener('click', addToCartClicked);
}
document.getElementsByClassName('btn-purchase')[0].addEventListener('click', purchaseClicked);
}
function purchaseClicked(){
alert('Thank you for your purchase');
var cartItems = document.getElementsByClassName('cart-cards')[0];
while(cartItems.hasChildNodes()){
cartItems.removeChild(cartItems.firstChild)
}
updateCartTotal()
}
function removeCartItem(event){
let buttonClicked = event.target;
buttonClicked.parentElement.parentElement.remove();
updateCartTotal();
}
function addToCartClicked(event){
let button = event.target;
let cartItem = button.parentElement;
let title = cartItem.getElementsByClassName('dom-title')[0].innerText;
let price = cartItem.getElementsByClassName('item-price')[0].innerText;
addItemToCart(title, price);
updateCartTotal();
// HERE
ready();
}
function addItemToCart(title, price){
let basketItem = document.createElement('div');
//CartItems was changed to cartCards
let cartCards = document.getElementsByClassName('cart-cards')[0];
let cartItemNames = cartCards.getElementsByClassName('cart-domain');
for(let i = 0; i < cartItemNames.length; i++){
if(cartItemNames[i].innerText == title){
alert('This item is already added to the cart');
return;
}
}
let cartContents = `
<br>
<br>
<div class="cart-card">
<h5 class="cart-domain">${title}<span style="color: gray">.crypto</span></h5>
<hr style="width: 80%; margin: auto;">
<p class="cart-text">No recurring fees. This domain will never expire. You will own the domain outright.</p>
<br>
<br>
<button class="cart-purchase">Buy it now</button>
<div class="price-cart-item">
<br>
<br>
<p>
Price: <span class="cart-item-price">${price}</span>
</p>
<br>
<button class="remove-btn">Remove <i class="fas fa-trash"></i></button>
</div>
<p class="cart-text">Renewal Cost: $0.00</p>
</div>`;
basketItem.innerHTML = cartContents;
cartCards.append(basketItem);
cartCards.getElementsByClassName('remove-btn')[0].addEventListener('click', removeCartItem);
}
function updateCartTotal(){
let cartItemContainer = document.getElementsByClassName('cart-cards')[0];
let cartCards = cartItemContainer.getElementsByClassName('cart-card');
let total = 0;
for(let i =0; i < cartCards.length; i++){
let cartCard = cartCards[i];
let priceElement = cartCard.getElementsByClassName('cart-item-price')[0];
let price = parseFloat(priceElement.innerText.replace('$', '').replace(',', ''));
total += price;
}
total = Math.round(total * 100) / 100;
let commasAdded = total.toLocaleString();
document.getElementsByClassName('basket-total')[0].innerText = '$' + commasAdded;
}
<!--Products for sale -->
<div class="domain-item">
<p class="domain-aspect domain-title"><strong class="linked"><span class="dom-title">happy</span><span style="color: #1a6db7">.com</span></strong> <span class="item-price">$100,000</span></p>
<button class="domain-aspect add-to-cart-btn">Add To Cart</button>
</div>
<div class="domain-item">
<p class="domain-aspect domain-title"><strong class="linked"><span class="dom-title">exchange</span><span style="color: #1a6db7">.com</span></span></strong> <span class="item-price">$100,000</span></p>
<button class="domain-aspect add-to-cart-btn">Add To Cart</button>
</div>
<div class="domain-item">
<p class="domain-aspect domain-title"><strong class="linked"><span class="dom-title">bestdadever</span><span style="color: #1a6db7">.com</span></span></strong> <span class="item-price">$100,000</span></p>
<button class="domain-aspect add-to-cart-btn">Add To Cart</button>
</div>
<!--Cart-->
<div class="cart-total-text">
<p>Your Items</p>
<p>Total: <span class="basket-total"></span></p>
</div>
<div class="cart-cards">
</div>
I have a view which polls an endpoint every 30 seconds and updates if there are changes. In the same view I have a div which is shown/hidden every 7 seconds. The timers are started at the same time.
The first few times it runs, it runs perfectly. It's not until the first 30s timer polls again that it basically starts flickering back and forward every 2 seconds - which it shouldn't.
component.ts
getScreen(tapCode) {
timer(0, 30000)
.pipe(mergeMap(() => this.dataService.get_screen(tapCode)))
.subscribe(objectResp => {
this.callResp = objectResp.status;
this.polledObj = objectResp.items;
this.landing = false;
this.loaded = true;
this.unavailable = objectResp.items.unavailable;
localStorage.setItem('ontapCode', tapCode);
this.getAds(this.polledObj);
});
}
getAds(polledObj) {
this.showAd = false;
this.adTimer = timer(0, 7000);
this.adSubscription = this.adTimer.subscribe(() => {
if(this.timerCount >= this.polledObj.adverts.length) {
this.timerCount = 0;
}
if(this.timerCount <= this.polledObj.adverts.length) {
this.adImage = this.polledObj.adverts[this.timerCount].filename;
this.timerCount++;
}
this.showAd = !this.showAd;
});
}
component.html
<div *ngIf="callResp === 'OK'" class="tap">
<div *ngIf="unavailable === '1' || unavailable === 1" class="object-unavailable">
<img src="./assets/unavailable.png" class="unavailable-img">
</div>
<div *ngIf="unavailable === '0' || unavailable === 0">
<img src={{polledObj.img}} class="img-object">
<div class="container">
<div *ngIf="showAd === true">
<div class="advertisement">
<img src={{adImage}}" class="img-ad">
</div>
</div>
<div *ngIf="showAd === false">
<div class="object-detail-container">
<h3 (click)="resetStorage()" class="object-name text-white">{{polledObj.object_name}}</h3>
<h4 class="text-white object-brewery">{{polledObj.brewery}}</h4>
<h4 class="text-white object-style">{{polledObj.style}} - {{polledObj.abv}}%</h4>
<div class="object-sizes" *ngFor="let size of polledObj.sizes">
<span class="object-size-name">{{size.name}}: </span>
<span class="object-size-volume"> {{size.volume*1000}}ml </span>
<span class="object-size-price"> ${{getPrice(size.price)}} </span>
<span class="object-size-std"> {{getSizeStd(size)}} </span>
<span class="object-size-std-drinks"> std drinks</span>
</div>
</div>
</div>
</div>
</div>