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/
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();
});
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.
I'm having trouble understanding why my onclick buttons are not working. My onclick buttons are within a JS function which modifies the HTML.
Here is the function which includes the onclick buttons:
const bookmarkHTML = (bookmark) => {
let html = '';
if (bookmark.url.includes('https://') || bookmark.url.includes('http://')) {
const li = `
<li>
<div class="row card-margin">
<div class="col s12 m12 card-padding">
<div class="card-panel teal card-size">
<img src='${'https://www.google.com/s2/favicons?domain_url=' + bookmark.url}' alt='icon' class='img-size'>
<a class='white-text' href='${bookmark.url}' target='_blank'>${bookmark.website}</a>
<button class='btn-flat waves-light btn-small right' onclick='switchCategory(bookmark)'><i class='material-icons left'>compare_arrows</i>switch</button>
</div>
</div>
</div>
</li>
`;
html += li;
} else {
const li = `
<li>
<div class="row card-margin">
<div class="col s12 m12 card-padding">
<div class="card-panel teal card-size">
<img src='${'https://www.google.com/s2/favicons?domain_url=' + bookmark.url}' alt='icon' class='img-size'>
<a class='white-text' href='${'https://' + bookmark.url}' target='_blank'>${bookmark.website}</a>
<button class='btn-flat waves-light btn-small right' onclick='switchCategory(bookmark)'><i class='material-icons left'>compare_arrows</i>switch</button>
</div>
</div>
</div>
</li>
`;
html += li;
}
console.log('HTML:', html);
return html;
}
Here is the function called in onclick:
switchCategory = (bookmark) => {
if (bookmark.favorite) {
bookmark.favorite = false;
} else {
bookmark.favorite = true;
}
}
If needed, here is the function which calls the bookmarkHTML function:
const setupBookmarks = (data) => {
let favoritesHTML = '';
let bookmarksHTML = '';
if (data.length) {
data.forEach(doc => {
const bookmark = doc.data();
if (bookmark.favorite) {
favoritesHTML += bookmarkHTML(bookmark);
} else {
bookmarksHTML += bookmarkHTML(bookmark);
}
})
}
favoriteList.innerHTML = favoritesHTML;
bookmarkList.innerHTML = bookmarksHTML;
}
When I click on the button with onclick, I get this error:
Uncaught ReferenceError: bookmark is not defined
at HTMLButtonElement.onclick (index.html:1)
Thanks for any help.
It seems that is happening because when you are passing an object inside template literals switchCategory(bookmark) this object is converted to [object Object]. A workaround for this may be converting that object to string switchCategory(${JSON.stringify(bookmark)}) but it won't do the job in your case because you are mutating that object later. I think that adding EventListener may be the way to resolve this. I also found similar problem so u can get more information about that and maybe a better solution.
I have a simple HTML form which has an event listener binded to it and when you click on the button inside the form that has a class of 'booking__form__counter--increase' this should increase the input field value by 1. It calls a javascript function named 'increaseCounter()' I declare a variable that points to this value but when i try to use the variable to increment it, it doesn't work. If i use the methods in the variable directly it works? I am missing something simple here but i cannot work out what.
let bookingForm = document.querySelector('.booking__form');
bookingForm.addEventListener('click', function (e) {
let target = e.target;
let inputCounterValue = target.parentElement.firstElementChild.value;
let inputMaxCounterValue = target.parentElement.firstElementChild.dataset.maxCount;
let showCounterValue = target.parentElement.firstElementChild.nextElementSibling.textContent;
if (target.classList.contains('booking__form__counter--increase')) {
increaseCounter();
}
function increaseCounter() {
if (inputCounterValue === inputMaxCounterValue) {
return;
} else {
//does not update
inputCounterValue++;
showCounterValue = inputCounterValue;
//this does update
target.parentElement.firstElementChild.value++;
target.parentElement.firstElementChild.nextElementSibling.textContent = target.parentElement.firstElementChild.value;
}
}
});
<form class="booking__form">
<div class="container">
<div class="booking__form__group">
<div class="booking__form__section booking__form__section--arrival">
<div class="booking__form__control">
<label for="arrival">Arrival Date</label>
<div class="booking__form__counter">
<span class="booking__form__counter--value">0</span>
<div class="booking__form__counter--button booking__form__counter--increase">
<svg class="fal fa-chevron-up"></svg>
</div>
<div class="booking__form__counter--button booking__form__counter--decrease">
<svg class="fal fa-chevron-down"></svg>
</div>
</div>
</div>
</div>
<div class="booking__form__section booking__form__section--duration">
<div class="booking__form__control">
<label for="arrival">Nights</label>
<div class="booking__form__counter">
<input type="hidden" name="duration" value="1" data-max-count="21">
<span class="booking__form__counter--value">1</span>
<div class="booking__form__counter--button booking__form__counter--increase">
<svg class="fal fa-chevron-up"></svg>
</div>
<div class="booking__form__counter--button booking__form__counter--decrease">
<svg class="fal fa-chevron-down"></svg>
</div>
</div>
</div>
</div>
<div class="booking__form__section booking__form__section--adults">
<div class="booking__form__control" id="booking--adults">
<label for="arrival">Adults</label>
<div class="booking__form__counter">
<input type="hidden" name="adults" value="1" data-max-count="8">
<span class="booking__form__counter--value">1</span>
<div class="booking__form__counter--button booking__form__counter--increase">
<svg class="fal fa-chevron-up"></svg>
</div>
<div class="booking__form__counter--button booking__form__counter--decrease">
<svg class="fal fa-chevron-down"></svg>
</div>
</div>
</div>
</div>
<div class="booking__form__section booking__form__section--children">
<div class="booking__form__control" id="booking--children">
<label for="arrival">Children</label>
<div class="booking__form__counter">
<input type="hidden" name="children" value="0" data-max-count="5">
<span class="booking__form__counter--value">0</span>
<div class="booking__form__counter--button booking__form__counter--increase">
<svg class="fal fa-chevron-up"></svg>
</div>
<div class="booking__form__counter--button booking__form__counter--decrease">
<svg class="fal fa-chevron-down"></svg>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
UPDATED Javascript
I have had a play around and added my updated javascript below which now seems to be working ok. I removed the data attributes 'data-max-count' and just added in the 'max' attribute and changed the variable decelerations around.
let bookingForm = document.querySelector('.booking__form');
bookingForm.addEventListener('click', function (e) {
let target = e.target;
let input = target.parentElement.firstElementChild;
let displayValue = target.parentElement.firstElementChild.nextElementSibling;
if (target.classList.contains('booking__form__counter--increase')) {
increaseCounter();
} else if (target.classList.contains('booking__form__counter--decrease')) {
decreaseCounter();
}
function increaseCounter() {
if (input.value === input.max) {
return;
} else {
input.value++;
displayValue.textContent = input.value;
}
}
});
I re-wrote your js and it now works.
You had some issues with your selectors and the way you updated the values.
I associated the max-count with the hidden input you have there and read the data-max-count attribute value. If this is not present then the auto-increment doesn't work because I set the initial value of inputMaxCounterValue equal to 0.
Keep in mind that I only update what the user sees and not the input value.
let bookingForm = document.querySelector('.booking__form');
bookingForm.addEventListener('click', function (e) {
let target = e.target;
let parentElem = target.parentElement;
let inputCounterValue = 0;
let valueContainer = parentElem.querySelector('.booking__form__counter--value');
if (typeof valueContainer.textContent!=="undefined") {
inputCounterValue = parseInt(valueContainer.textContent,10);
}
if (target.classList.contains('booking__form__counter--increase')) {
increaseCounter(valueContainer);
}
function increaseCounter(element) {
let inputMaxCounterValue = 0;
let parentElem = target.parentElement;
if (typeof parentElem.querySelector('input')!=="undefined" && parentElem.querySelector('input')!==null) {
inputMaxCounterValue = parentElem.querySelector('input').getAttribute("data-max-count");
}
if (inputCounterValue === inputMaxCounterValue) {
return;
} else {
//does not update
inputCounterValue++;
showCounterValue = inputCounterValue;
//this does update
element.textContent = inputCounterValue;
}
I have two div html elements with different id and here I am using spinner. Whenever values in the spinner input changes alert box will be displayed.
HTML code
<div id="accordion2" class="panel-group" style="display: block;">
<div id="accordion2" class="panel-group">
<div id="Tea">
<div class="spinner Tea input-group ">
<input type="text" id = "servings" class="form-control input- sm" value="Tea"/>
<div class="input-group-btn-vertical">
<button class="btn Tea btn-default">
<i class="fa fa-caret-up"></i>
</button>
<button class="btn Tea btn-default">
<i class="fa fa-caret-down"></i>
</button>
</div>
<h4 id="energy" class="Tea"> Tea </h4>
</div>
<div id="Coffee">
<div class="spinner Coffee input-group ">
<input type="text" id = "servings" class="form-control input-sm" value="Coffee"/>
<div class="input-group-btn-vertical">
<button class="btn Coffee btn-default">
<i class="fa fa-caret-up"></i>
</button>
<button class="btn Coffee btn-default">
<i class="fa fa-caret-down"></i>
</button>
</div>
<h4 id="energy" class="Coffee">Coffee</h4>
</div>
</div>
</div>
JQuery code
$(function(){
$('.spinner:first-of-type input').on('click', function() {
$('.spinner:first-of-type input').val(parseInt($('.spinner:first-of-type input').val(), 10) + 1);
var val = $('.spinner:first-of-type input').val();
changeValues(val);
});
$('.spinner:last-of-type input').on('click', function() {
$('.spinner input').val( parseInt($('.spinner input').val(), 10) - 1);
});
function changeValues(value){
alert($('#energy').attr('class').split(' '));
};
});
But in the alert box whenever I click the spinner up arrow only Tea is displayed.
what I expect is when the spinner is clicked from Tea div tea should be displayed and when from coffee , coffee should be displayed.Please help me out
I'm not sure I totally got what you are trying to do, but it seems to me that you want to increment and decrement number of beverage cups on up/down buttons click. For this you would better modify mark up a little (remove duplicated ids, add classes for convenience). And I may look like this then:
$(function() {
$('.spinner').on('click', '.servings', function(e) {
$(this).val(parseInt($(this).val() || 0, 10) + 1);
var val = $(this).val();
changeValues.call(e.delegateTarget, val);
})
.on('click', '.up', function(e) {
$(e.delegateTarget).find('.servings').val(function() {
return ++this.value;
});
})
.on('click', '.down', function(e) {
var $input = $(e.delegateTarget).find('.servings');
if (+$input.val() > 1) {
$input.val(function() {
return --this.value;
});
}
});
function changeValues(value) {
var type = $(this).find('.energy').data('type');
alert(type);
};
});
Demo: http://plnkr.co/edit/9vXC0RipxkzqhXrHJAKD?p=preview
try this:
$(function () {
$('.spinner').each(function () {
var $el = $(this),
$buttons = $el.find('button'),
$h4 = $el.find('h4'),
input = $el.find('input').get(0);
function showAlert() {
alert($h4.get(0).className);
}
$buttons.eq(0).on('click', function (event) {
event.preventDefault();
input.value = (parseInt(input.value, 10) || 0) + 1;
showAlert();
});
$buttons.eq(1).on('click', function (event) {
event.preventDefault();
input.value = (parseInt(input.value, 10) || 0) - 1;
});
});
});
JSFiddle http://jsfiddle.net/yLtn57aw/2/
Hope this helps