Undo the last click on button using JQuery - javascript

I have a code like this -
<button class="btn">New York</button>
<button class="btn">Amsterdam</button>
<button class="btn">New Jersey</button>
<button class="btn">Alabama</button>
<button class="btn">Michigan</button>
<button id="undo" class="undo-selection">Undo last selection</button>
and have below code to check the order at which these buttons are clicked.
var click = 0;
var buttons = document.querySelectorAll('button.btn');
buttons.forEach(button => {
button.addEventListener('click', function(){
var current = button.innerText;
var existingClicks = current.split(" ");
if(existingClicks.length > 1) {
button.innerText += ` & ${++click}`;
}
else {
button.innerText = `clicked = ${++click}`;
}
});
});
By using the Undo button I want to clear last selection made and should be able to select new button. Any help is appreciated.

Maybe something like this:
let click = 0;
const buttons = document.querySelectorAll('button.btn');
const clicks = [];
buttons.forEach((button, index) => {
button.addEventListener('click', function(){
const clicked = clicks.includes(index);
clicks.push(index);
if (!clicked) {
button.innerText = `clicked = ${++click}`;
} else {
button.innerText += ` & ${++click}`;
}
});
});
document.getElementById('undo').addEventListener('click', () => {
if (!clicks.length) {
return;
}
const lastClicked = clicks.pop();
click--;
let text = buttons[lastClicked].innerText.split('&');
text.pop();
text = text.join('&');
buttons[lastClicked].innerText = text || buttons[lastClicked].getAttribute('data-text');
});
<button class="btn" data-text="New York">New York</button>
<button class="btn" data-text="Amsterdam">Amsterdam</button>
<button class="btn" data-text="New Jersey">New Jersey</button>
<button class="btn" data-text="Alabama">Alabama</button>
<button class="btn" data-text="Michigan">Michigan</button>
<button id="undo" class="undo-selection">Undo last selection</button>

Related

JS dynamically created area with buttons is missing when to-do task is edited (and not always)

I wanted to create my own To-do list app and I have a problem when I edit a task the area with three buttons (accept, edit and cancel btns) sometimes goes missing.
I'm trying to figure out what's happening with it in the dev tools and it looks like when there are e.g. two tasks (two li elements) the div area with buttons move from one to another and the second li has two divs and the first li (edited one) it left with no buttons at all.
Here's my code, please excuse any weird things you may find there (I'm not really experienced).
const inputField = document.querySelector('.todo__input')
const addBtn = document.querySelector('.todo__btn')
const ulList = document.querySelector('.todo__list')
const infoParagraph = document.querySelector('.todo__info-paragraph')
const popupDiv = document.querySelector('.pop-up')
const popupAcceptBtn = document.querySelector('.edit-accept')
const popupCancelBtn = document.querySelector('.edit-cancel')
const popupInput = document.querySelector('.edit__input')
const popupInfo = document.querySelector('.edit__info')
let liItem
let acceptButton
let editButton
let cancelButton
let editedTodoTask
let editBtnToBeDisabled
const createLiSpace = () => {
const div = document.createElement('div')
div.classList.add('todo__list-buttons')
liItem.append(div)
acceptButton = document.createElement('button')
acceptButton.classList.add('todo__list-btn')
acceptButton.classList.add('todo__list-btn--accept')
acceptButton.innerHTML = '<i class="fa-solid fa-check"></i>'
editButton = document.createElement('button')
editButton.classList.add('todo__list-btn')
editButton.classList.add('todo__list-btn--edit')
editButton.innerHTML = '<i class="fa-solid fa-pencil"></i>'
cancelButton = document.createElement('button')
cancelButton.classList.add('todo__list-btn')
cancelButton.classList.add('todo__list-btn--cancel')
cancelButton.innerHTML = '<i class="fa-solid fa-xmark"></i>'
div.append(acceptButton, editButton, cancelButton)
acceptButton.addEventListener('click', completeTask)
editButton.addEventListener('click', showPopup)
cancelButton.addEventListener('click', deleteTask)
}
const addTask = () => {
if (inputField.value !== '') {
liItem = document.createElement('li')
liItem.classList.add('todo__list-item')
liItem.textContent = inputField.value
createLiSpace()
ulList.appendChild(liItem)
inputField.value = ''
infoParagraph.textContent = ''
} else if (inputField.value == '') {
infoParagraph.style.color = 'rgb(206, 99, 28)'
infoParagraph.textContent = 'Please type in your task first!'
}
}
const showPopup = e => {
editedTodoTask = e.target.closest('li')
popupDiv.style.visibility = 'visible'
popupInfo.textContent = ''
popupInput.value = editedTodoTask.firstChild.textContent
}
const changeTodoTask = () => {
if (popupInput.value !== '') {
editedTodoTask.textContent = popupInput.value
createLiSpace()
closePopup()
popupInput.value = ''
} else {
popupInfo.textContent = 'Please type in some text here...'
}
}
const enterAddTask = (e) => {
if (e.key == "Enter") {
addTask()
}
}
const completeTask = e => {
editedTodoTask = e.target.closest('li')
editedTodoTask.classList.toggle('crossline')
}
const closePopup = () => {
popupDiv.style.visibility = 'hidden'
}
const deleteTask = e => {
ulList.removeChild(e.target.closest('li'))
}
popupAcceptBtn.addEventListener('click', changeTodoTask)
popupCancelBtn.addEventListener('click', closePopup)
addBtn.addEventListener('click', addTask)
inputField.addEventListener('keyup', enterAddTask)
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css" integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<div class="container">
<div class="todo-top-section">
<h1 class="todo__header">My to-do list</h1>
<input type="text" placeholder="Type your task here..." class="todo__input">
<button class="todo__btn"><img class="todo__blob" src="/src/img/blobanimation.svg" alt="">add</button>
</div>
<div class="todo-bottom-section">
<h2 class="todo__heading">Task list:</h2>
<p class="todo__info-paragraph">No tasks here yet</p>
<ul class="todo__list">
</ul>
</div>
<div class="pop-up">
<h3 class="edit__header">Want to change anything in here?</h3>
<p class="edit__info"></p>
<div class="edit-container">
<input type="text" class="edit__input" placeholder="Type in your change...">
<div class="todo__list-buttons">
<button class="todo__list-btn todo__list-btn--accept edit-accept">Accept <i class="fa-solid fa-check"></i></button>
<button class="todo__list-btn todo__list-btn--cancel edit-cancel">Cancel <i class="fa-solid fa-xmark"></i></button>
</div>
</div>
</div>
Could you please check and specify what is causing that trouble?
You can find my code here too: https://codepen.io/re_aleksandra/pen/PoebEPv
Thank you!

HTML Checkbox "onclick" Create Button issue

So i have following objectives from the checkbox click event
1] Create A Button having id = 'id-of-checkbox'+'some-character-here' in specified div
2] Clicking On That Particular Button Will Remove The Button As Well As Checkbox tick related to it
3] If User wants to remove button in specified div through unchecking the checkbox it should be done
4] And If User again checks the checkbox button should be created in specified div
Now i have achieved first 3 objectives and im having issue with 4th one , i.e
if i click on checkbox again after unticking it button is not getting created and console doesnt return any error associated with it.. please help
Here Is My HTML Code
<div id="filterDropArea container">
<input type="checkbox" name="priceFilter" id="priceFilter" class="btn" onclick="updateValue(this.id,this.name)">
Price Filter
</div>
<div id="DropArea">
</div>
Here is My Javascript Code
var objTo = document.getElementById('DropArea');
var checked = ""
function updateValue(id,name)
{
if(document.getElementById(id).checked)
{
checked='yes'
}
else if(!document.getElementById(id).checked)
{
checked='no'
}
if(checked=='yes')
{
addButton(id,name);
}
else if(checked=='no')
{
removeButton(id,name);
}
}
function addButton(id,name)
{
var nameOfButton = name+'X';
var idofButton = id+'11';
var btn = document.createElement("BUTTON");
btn.innerHTML=nameOfButton;
btn.setAttribute("class","btnCancel");
btn.setAttribute("id",idofButton);
btn.setAttribute("onclick","someMsg(this.id)")
objTo.appendChild(btn);
}
function removeButton(id,name)
{
var idofButton = id+'11'
if(document.getElementById('DropArea').contains(document.getElementById(idofButton)))
{
document.getElementById('DropArea').remove(document.getElementById(idofButton));
console.log('Button Removed');
}
}
function someMsg(id)
{
var name = id.substring(0,id.length-2);
document.getElementById(id).remove();
document.getElementById(name).checked=false;
console.log('Deleted');
}
Another approach to achieving the same result:
const dropArea = document.querySelector("#dropArea");
const checkbox = document.querySelector("#priceFilter");
checkbox.addEventListener("change", function(e) {
if (this.checked) {
const btn = createSpecificButton();
dropArea.appendChild(btn);
} else {
const btn = dropArea.querySelector("button");
dropArea.removeChild(btn);
}
});
const createSpecificButton = () => {
const btn = document.createElement("button");
btn.innerText = "Click Here";
btn.addEventListener("click", function(e) {
checkbox.checked = false;
this.remove();
});
return btn;
};
<div id="filterDropArea container">
<input type="checkbox" name="priceFilter" id="priceFilter" /> Price Filter
</div>
<div id="dropArea"></div>
Element.remove() don't have any parameters, so when you call by your way, it will remove DropArea element (includes children, like idofButton).
Solution: Change the below line
document.getElementById('DropArea').remove(document.getElementById(idofButton));
To
document.getElementById(idofButton).remove();
var objTo = document.getElementById('DropArea');
var checked = ""
function updateValue(id, name) {
if (document.getElementById(id).checked) {
checked = 'yes'
} else if (!document.getElementById(id).checked) {
checked = 'no'
}
if (checked == 'yes') {
addButton(id, name);
} else if (checked == 'no') {
removeButton(id, name);
}
}
function addButton(id, name) {
var nameOfButton = name + 'X';
var idofButton = id + '11';
var btn = document.createElement("BUTTON");
btn.innerHTML = nameOfButton;
btn.setAttribute("class", "btnCancel");
btn.setAttribute("id", idofButton);
btn.setAttribute("onclick", "someMsg(this.id)")
objTo.appendChild(btn);
}
function removeButton(id, name) {
var idofButton = id + '11'
if (document.getElementById('DropArea').contains(document.getElementById(idofButton))) {
document.getElementById(idofButton).remove();
console.log('Button Removed');
}
}
function someMsg(id) {
var name = id.substring(0, id.length - 2);
document.getElementById(id).remove();
document.getElementById(name).checked = false;
console.log('Deleted');
}
<div id="filterDropArea container">
<input type="checkbox" name="priceFilter" id="priceFilter" class="btn" onclick="updateValue(this.id,this.name)"> Price Filter
</div>
<div id="DropArea">
</div>

is there any method in javascript to operate a function singly for one HTML element?

I have three box in my web page , each box includes a + button , a - button and a span with pre-assigned value as 0.
I want when I click on + or - button, the value of span get one more or less according to times of clicking + or -.
but my code doesnt work well.
what should I do ?
Thanks.
<div class="box">
<button class="minus-btn" type="button">-</button>
<span class="display-num">0</span>
<button class="plus-btn" type="button">+</button>
</div>
<div class="box">
<button class="minus-btn" type="button">-</button>
<span class="display-num">0</span>
<button class="plus-btn" type="button">+</button>
</div>
<div class="box">
<button class="minus-btn" type="button">-</button>
<span class="display-num">0</span>
<button class="plus-btn" type="button">+</button>
</div>
function $(query) {
return document.querySelector(query);
}
function $All(query) {
return document.querySelectorAll(query);
}
const box = $All('.box');
const plusBtn = $All('.plus-btn');
const minusBtn = $All('.minus-btn');
const displayNum = $All('.display-num');
box.forEach((e) => {
e.addEventListener('click', (el) => {
if (el.target.classList.contains('plus-btn')) {
let num = 0;
displayNum.forEach((e) => {
e.innerHTML = num++;
})
} else if (el.target.classList.contains('minus-btn')) {
let num = 0;
displayNum.forEach((e) => {
e.innerHTML = num--;
})
}
}, false)
})
It is probably easier to react on the actual button being pressed, rather than checking the boxes etc, try the following:
plusBtn.forEach((e, idx) => {
e.addEventListener(
'click',
(el) => {
calcIt(displayNum[idx], 1);
},
false
);
});
minusBtn.forEach((e, idx) => {
e.addEventListener(
'click',
(el) => {
calcIt(displayNum[idx], -1);
},
false
);
});
function calcIt(element, value) {
var num = element.innerHTML;
element.innerHTML = (+num) + value;
}
Remove the block:
box.forEach((e) => {
e.addEventListener('click', (el) => {
if (el.target.classList.contains('plus-btn')) {
let num = 0;
displayNum.forEach((e) => {
e.innerHTML = num++;
})
} else if (el.target.classList.contains('minus-btn')) {
let num = 0;
displayNum.forEach((e) => {
e.innerHTML = num--;
})
}
}, false)
})
Stackblitz:
https://jquery-rfrzsp.stackblitz.io
(https://stackblitz.com/edit/jquery-rfrzsp)

change list item to be an input text

I am working on "to do list" using Vanilla JavaScript and stuck with edit button.
This is what I have done so far.
// console.log("Hello from inside");
const input = document.getElementById("inputText");
const display = document.getElementById("display");
const displayDone = document.getElementById("display-done");
const button = document.getElementById("addButton");
const deleteAll = document.getElementById("delete-icon");
// const ul = document.getElementById("display");
// Create and Remove list item
function createItem() {
let listItem = document.createElement("li");
listItem.className = "create";
listItem.appendChild(document.createTextNode(input.value));
display.appendChild(listItem);
input.value = "";
let editButton = document.createElement("button");
editButton.innerText = "edit";
editButton.className = "edit";
editButton.addEventListener("click", (e) => {
//console.log(e.currentTarget.parentNode);
// 1. When edit button is clicked, change list item to be an input text. <input type="text" value="my to do task"/>
// 2. Change edit button to be something like "complete" button
editButton.innerText = "complete";
// 3. When complete button is clicked, change the input item to be a list item again with the updated text.
editButton.addEventListener("click", (e) => {
editButton.innerText = "edit";
});
});
let removeTask = document.createElement("input");
removeTask.setAttribute("type", "button");
removeTask.setAttribute("value", "X");
removeTask.setAttribute("id", "removeButton");
removeTask.addEventListener("click", (e) => {
listItem.parentNode.removeChild(listItem);
});
listItem.appendChild(editButton);
listItem.appendChild(removeTask);
listItem.addEventListener("dblclick", (e) => {
displayDone.appendChild(listItem);
listItem.style.backgroundColor = "#54e346";
listItem.style.textDecoration = "line-through";
editButton.style.display = "none";
});
}
//Make sure user fill the input
function addAfterClick() {
if (input.value.length > 0) {
createItem();
} else {
alert("Write something mate!");
}
}
//List item can be added with "Enter" as well
function addWithEnter(event) {
if (event.keyCode === 13) {
addAfterClick();
}
}
// Remove all with user approve
function removeAll(event) {
let answer = prompt(`Type "Delete All" If you are that sure!`);
if (answer === "Delete All") {
display.style.display = "none";
location.reload();
} else {
alert("Try One More Time");
}
}
//Event Listeners
button.addEventListener("click", addAfterClick);
input.addEventListener("keyup", addWithEnter);
deleteAll.addEventListener("click", removeAll);
<div class="main-container">
<h2 class="title">to do list <i class="fas fa-pencil-alt"></i></h2>
<div class="content">
<input
id="inputText"
type="text"
placeholder="Add to your list..."
maxlength="20"
/>
<i id="addButton" class="fas fa-plus"></i>
<div class="remove-container">
<i id="delete-icon" class="far fa-trash-alt"></i>
<p id="remove-text">Delete All</p>
</div>
<ul id="display"></ul>
</div>
<div class="completed">
<h2 class="title-done">
completed tasks <i class="far fa-check-circle"></i>
</h2>
<ul id="display-done"></ul>
</div>
</div>
What I want to do it;
When edit button is clicked, change list item to be an input text.
Change edit button to be something like "complete" button
When complete button is clicked, change the input item to be a list item again with the updated text.
I have tried ChildNode.replaceWith() but did not work. Am I on the right path? and also what direction(s) I should follow. Thanks in advance!
My approach is to add an input field everytime you create an item:
at initial insertion hide the input field
on click on the edit button show the input and change the textNode
after you editing
console.log("Hello from inside");
const input = document.getElementById("inputText");
const display = document.getElementById("display");
const displayDone = document.getElementById("display-done");
const button = document.getElementById("addButton");
const deleteAll = document.getElementById("delete-icon");
// const ul = document.getElementById("display");
// create edit input and hide the input at first
const editInput=document.createElement("input");
editInput.setAttribute("hidden",true);
// eventhandler for editInput
function editItem(e,item){
// remove the current text node
e.target.parentNode.removeChild(e.target.parentNode.childNodes[0])
// insert at the beginning of the childNodes
e.target.parentNode.prepend( e.target.value)
e.target.setAttribute("hidden",true)
}
// Create and Remove list item
function createItem() {
let listItem = document.createElement("li");
listItem.className = "create";
listItem.appendChild(document.createTextNode(input.value));
display.appendChild(listItem);
input.value = "";
let editButton = document.createElement("button");
editButton.innerText = "edit";
editButton.className = "edit";
editInput.value=""
editButton.addEventListener("click", (e) => {
// 1. When edit button is clicked, change list item to be an input text. <input type="text" value="my to do task"/>
// 2. Change edit button to be something like "complete" button
// appended edit input
listItem.append(editInput)
if(e.target.innerText === "edit"){
editInput.removeAttribute("hidden",false)
e.target.innerText = "complete";
}else{
e.target.innerText = "edit";
}
// add the event handler for the Editinput
editInput.addEventListener("change",(e)=>editItem(e,listItem));
editInput.value=""
// 3. When complete button is clicked, change the input item to be a list item again with the updated text.
});
let removeTask = document.createElement("input");
removeTask.setAttribute("type", "button");
removeTask.setAttribute("value", "X");
removeTask.setAttribute("id", "removeButton");
removeTask.addEventListener("click", (e) => {
listItem.parentNode.removeChild(listItem);
});
listItem.appendChild(editButton);
listItem.appendChild(removeTask);
listItem.addEventListener("dblclick", (e) => {
displayDone.appendChild(listItem);
listItem.style.backgroundColor = "#54e346";
listItem.style.textDecoration = "line-through";
editButton.style.display = "none";
});
}
//Make sure user fill the input
function addAfterClick() {
if (input.value.length > 0) {
createItem();
} else {
alert("Write something mate!");
}
}
//List item can be added with "Enter" as well
function addWithEnter(event) {
if (event.keyCode === 13) {
addAfterClick();
}
}
// Remove all with user approve
function removeAll(event) {
let answer = prompt(`Type "Delete All" If you are that sure!`);
if (answer === "Delete All") {
display.style.display = "none";
location.reload();
} else {
alert("Try One More Time");
}
}
//Event Listeners
button.addEventListener("click", addAfterClick);
input.addEventListener("keyup", addWithEnter);
deleteAll.addEventListener("click", removeAll);
<div class="main-container">
<h2 class="title">to do list <i class="fas fa-pencil-alt"></i></h2>
<div class="content">
<input
id="inputText"
type="text"
placeholder="Add to your list..."
maxlength="20"
/>
<i id="addButton" class="fas fa-plus"></i>
<div class="remove-container">
<i id="delete-icon" class="far fa-trash-alt"></i>
<p id="remove-text">Delete All</p>
</div>
<ul id="display"></ul>
</div>
<div class="completed">
<h2 class="title-done">
completed tasks <i class="far fa-check-circle"></i>
</h2>
<ul id="display-done"></ul>
</div>
</div>
just a suggestion. you can use an input element for each item.
const input = document.getElementById("inputText");
const display = document.getElementById("display");
const displayDone = document.getElementById("display-done");
const button = document.getElementById("addButton");
const deleteAll = document.getElementById("delete-icon");
const createEditBtn = () => {
const editButton = document.createElement("button");
editButton.innerText = "edit";
editButton.className = "edit";
editButton.addEventListener("click", (e) => {
const btn = e.target;
const input = btn.parentElement.querySelector("input");
input.focus();
const previousVal = input.value;
input.addEventListener("keyup", (evt) => {
if (evt.keyCode === 13) {
if (input.value.trim() === "") {
input.value = previousVal;
}
input.disabled = true;
btn.disabled = false;
}
});
input.addEventListener("blur", () => {
input.disabled = true;
btn.disabled = false;
});
input.disabled = false;
btn.disabled = true;
});
return editButton;
}
const createRemoveBtn = () => {
const removeBtn = document.createElement("input");
removeBtn.setAttribute("type", "button");
removeBtn.setAttribute("value", "X");
removeBtn.addEventListener("click", (e) => {
e.target.parentElement.remove();
});
return removeBtn;
}
const createItem = () => {
const listItem = document.createElement("li");
listItem.innerHTML = `<input value="${input.value}" disabled=true>`;
display.appendChild(listItem);
input.value = "";
const editBtn = createEditBtn();
listItem.appendChild(editBtn);
listItem.appendChild(createRemoveBtn());
listItem.addEventListener("dblclick", (e) => {
displayDone.appendChild(listItem);
listItem.style.backgroundColor = "#54e346";
listItem.style.textDecoration = "line-through";
editBtn.style.display = "none";
});
}
const addAfterClick = () => {
if (input.value.length > 0) {
createItem();
} else {
alert("Write something mate!");
}
}
//List item can be added with "Enter" as well
const addWithEnter = (event) => {
if (event.keyCode === 13) {
addAfterClick();
}
}
// Remove all with user approve
const removeAll = (event) => {
const answer = prompt(`Type "Delete All" If you are that sure!`);
if (answer === "Delete All") {
display.innerHTML = "";
displayDone.innerHTML = "";
} else {
alert("Try One More Time");
}
}
//Event Listeners
button.addEventListener("click", addAfterClick);
input.addEventListener("keyup", addWithEnter);
deleteAll.addEventListener("click", removeAll);
<div class="main-container">
<h2 class="title">to do list <i class="fas fa-pencil-alt"></i></h2>
<div class="content">
<input id="inputText" type="text" placeholder="Add to your list..." maxlength="20" />
<i id="addButton" class="fas fa-plus">add Icon</i>
<div class="remove-container">
<i id="delete-icon" class="far fa-trash-alt">delete icon</i>
<p id="remove-text">Delete All</p>
</div>
<ul id="display"></ul>
</div>
<div class="completed">
<h2 class="title-done">
completed tasks <i class="far fa-check-circle"></i>
</h2>
<ul id="display-done"></ul>
</div>
</div>

eval() is returning a null value

I am trying to code a calculator but the equal button is not working with eval() and its giving null with (Invalid or unexpected token
at HTMLButtonElement.)
const btns = document.querySelectorAll('.btn');
const screen = document.querySelector('.screen');
const equalbtn = document.querySelector('.btnequal');
for(i=0; i<btns.length; i++){
btns[i].addEventListener('click', function(){
var number = this.getAttribute("data-num");
screen.value += number;
//console.log(screen.value);
})
}
equalbtn.addEventListener('click', function(){
if(screen.value === ''){
alert('Please select a value');
} else {
let value = eval(screen.value);
console.log(value);
screen.value = value;
}
})
This is an example of a running calculator based on your given code. Note that I never got any null value. Maybe your html code was wrong, you didn't add any.
const btns = document.querySelectorAll('.btn');
const screen = document.querySelector('.screen');
const equalbtn = document.querySelector('.btnequal');
let reset = false;
for(let i=0; i<btns.length; i++){
btns[i].addEventListener('click', function(){
let number = this.getAttribute("data-num");
if(reset){
screen.value = number;
reset = false;
}
else{
screen.value += number;
}
})
}
equalbtn.addEventListener('click', function(){
if(screen.value === ''){
alert('Please select a value');
} else {
let value = eval(screen.value);
screen.value = value;
reset = true;
}
})
<input class="screen" readonly="readonly" />
<button class="btn" data-num="1">1</button>
<button class="btn" data-num="2">2</button>
<button class="btn" data-num="3">3</button>
<button class="btn" data-num="+">+</button>
<button class="btn" data-num="-">-</button>
<button class="btn" data-num="*">*</button>
<button class="btn" data-num="/">/</button>
<button class="btnequal">=</button>

Categories