Using JavaScript to modify the content of html - javascript

Now I am doing a shopping cart in my project, when i click the add to cart button, then it will upload the data in localstorage, then i will create an element (product name, price, quantity and two increment and decrement button in the list) and this create process will be looped by the length of localstorage.
When I want to make click event on increment and decrement button, only the last row of increment and decrement button respond. For example, I have 3 rows in shopping cart, only the third row will show the proper result, the first two row have no response.
I would like to ask can you give me some suggestion, how to achieve my goal? Thanks!!!!!!!!!!!!!!
var ul = document.getElementById("cart")
for(var i=0;i<localStorage.length;i++){
var li = document.createElement("li");
var addBtn =document.createElement("BUTTON");
var dropBtn document.createElement("BUTTON");
addBtn.innerHTML = '+';
dropBtn.innerHTML = '-';
addBtn.id='addBtn'
var a = document.getElementById("addBtn")
addBtn.onclick = function(){
alert('here be addBtn');return false;
};
dropBtn.onclick = function(){
alert('here be dropBtn');return false;
};
ul.appendChild(addBtn);
ul.appendChild(dropBtn);
ul.appendChild(li);
}

You need to make some changes to work as expected:
Not to search/find button when you have its reference.
append a button to list i.e. li not to ul (Thanks CBroe).
I've taken some assumption like the localStorage length as 3 and added the text of the cart button.
const ul = document.querySelector("ul#cart");
for (var i = 0; i < 3; i++) {
var li = document.createElement("li");
var addBtn = document.createElement("BUTTON");
var dropBtn = document.createElement("BUTTON");
var text = document.createElement("span");
text.textContent = ` item${i+1} `
addBtn.innerHTML = '+';
dropBtn.innerHTML = '-';
addBtn.id = `addBtn${i+1}`;
dropBtn.id = `dropBtn${i+1}`;
addBtn.addEventListener('click', e => {
alert(`here be addBtn with id ${e.target.id}`);
})
dropBtn.addEventListener('click', e => {
alert(`here be dropBtn with id ${e.target.id}`);
})
li.appendChild(addBtn);
li.appendChild(text);
li.appendChild(dropBtn);
ul.appendChild(li);
}
<ul id="cart"></ul>

Related

Add class to clicked element, but remove from others

I'm creating some elements using JS, and need to add a class to each item when clicked, but remove it from the non clicked items. I'm sure this is a quick one, but I can't get my head around it.
let data = {
label:label,
somethingElse:"test",
id:id
};
sidebarOptions.push(data);
let ul = document.querySelector(".page-sidebar__options");
sidebarOptions.forEach(sidebarOption => {
let li = document.createElement('li'),
button = document.createElement('button'),
title = document.createElement('span'),
price = document.createElement('span')
ul.appendChild(li);
li.appendChild(button);
button.appendChild(title);
button.appendChild(price);
title.innerHTML = sidebarOption.label + sidebarOption.id;
price.innerHTML = '[Price]';
button.onclick = (event) => {
button.classList.add('selected');
};
})
So find if you have a selected button and remove the class
const currentlySelected = ul.querySelector('button.selected');
if (currentlySelected) currentlySelected.classList.remove('selected');

Why does deleting this element with a non-unique ID delete the one I want?

Pardon the bad title, it's hard to explain. If you know how to phrase it better, please comment and I will update as soon as I can.
So, I was messing around with a random generator site (perchance.org) and writing my own HTML/Javascript to make my generator work. It has a behavior that is what I want, but that shouldn't be happening according to my knowledge of HTML.
Let me explain with a minimal example.
The example code here is to produce a simple page that has a button.
This button should generate <input>s with <button>s next to them, attached with similar ID's.
The button, when clicked, deletes the <input> and <button>.
Here is a snippet to show you the code/let you reproduce the results:
<html>
<head>
<script>
var current_id = 0;
function add_input () {
var list = document.getElementById("list");
var input = document.createElement("input");
var delete_button = document.createElement("button");
var br = document.createElement("br");
input.id = "input_" + current_id;
delete_button.id = "button_" + current_id;
br.id = "br_" + current_id;
input.value = input.id;
delete_button.textContent = "Delete";
delete_button.onclick = function () {
delete_input(this.id.slice(7)) //To get the numerical ID
}
list.appendChild(input);
list.appendChild(delete_button);
list.appendChild(br);
current_id++;
}
function delete_input (id) {
var input = document.getElementById("input_"+id);
var button = document.getElementById("button_"+id);
var br = document.getElementById("br_"+id);
input.remove();
button.remove();
br.remove();
current_id--;
}
</script>
</head>
<body>
<div id="list">
</div>
<button onclick="add_input()">Add</button>
</body>
</html>
When you add two inputs, then delete the first, and add one more, it leaves you with two inputs using the same ID. It also leaves you with two buttons with the same ID. And yet, both buttons delete their intended target.
Why?
You really should delegate - here I wrap in a div that can be removed in one go
You can rename each input to have incremented IDs but just letting the cnt run, gives you unique IDs
let cnt = 0;
function add_input() {
var list = document.getElementById("list");
var div = document.createElement("div");
var input = document.createElement("input");
var delete_button = document.createElement("button");
var br = document.createElement("br");
input.id = "input_" + (cnt++)// list.querySelectorAll("div").length
input.value = input.id;
delete_button.textContent = "Delete";
delete_button.classList.add("delete")
div.appendChild(input);
div.appendChild(delete_button);
div.appendChild(br);
list.appendChild(div);
}
window.addEventListener("load", function() {
document.getElementById("list").addEventListener("click", function(e) {
const tgt = e.target;
if (tgt.classList.contains("delete")) tgt.closest("div").remove();
})
})
<div id="list">
</div>
<button onclick="add_input()">Add</button>
I changed your code to be more effective.
I'm not using IDs as they aren't adding any benefit instead making it more complex.
Instead I target the element via the event handler and an argument.
I also wrap each set of inputs/buttons in a div so I can just remove that div and it will remove all of the children.
function add_input() {
var list = document.getElementById("list");
var input = document.createElement("input");
var delete_button = document.createElement("button");
var br = document.createElement("br");
delete_button.textContent = "Delete";
delete_button.onclick = function(e) {
e.target.parentNode.remove();
}
var div = document.createElement("div");
div.appendChild(input);
div.appendChild(delete_button);
div.appendChild(br);
list.appendChild(div)
}
<div id="list">
</div>
<button onclick="add_input()">Add</button>

adding numbers from a counter but also creating new buttons with new counters

What i want to do is....when the counter button is clicked....increment a span to see how many times its been clicked but also create a new counter with its own incrementor
I have it somewhat working but when i create a new button....the counter doesnt work
anyone help me out with what im missing?
this is also done in vanilla js and html
template:
<div class="container">
<button type="button" id="increase" onClick="increaseCounter()">click</button>
<span id="amount"></span>
</div>
JS:
var counter = 0
function increaseCounter() {
let button = document.getElementById("increase");
let span = document.getElementById("amount");
counter += 1;
span.innerHTML = counter;
createNewButton();
}
function createNewButton() {
let container = document.getElementsByClassName("container")[0];
let btn = document.createElement("button");
btn.innerHTML = "new button";
btn.id = "increase";
container.appendChild(btn);
let span = document.createElement("span");
span.innerHTML = 0;
span.id = "amount";
container.appendChild(span);
}
LINK: https://codepen.io/zomdar/pen/ZEGPxNP?editors=1011
Here is a few things you should look for:
1- The event listener is only affected to the first button you assign as it is an inline event listener. So new buttons won't have the event listener.
2- If you want to have a new span containing the amount everyone, you must have a different ID for each span (or set the innerHTML directly as I did) or it will be the same span changing.
Note - The ID attribute should be unique in the page, every time you create a button the same ID is attributed. You should use the class attribute (non-unique value) or a different ID every time (e.g. "amount"+counter)
function increaseCounter() {
let button = document.getElementById("increase");
let span = document.getElementById("amount");
counter += 1;
// span.innerHTML = counter;
createNewButton();
}
function createNewButton() {
let container = document.getElementsByClassName("container")[0];
let btn = document.createElement("button");
btn.innerHTML = "new button";
btn.id = "increase"; // UNIQUE ID !!!
btn.onclick = increaseCounter;
container.appendChild(btn);
let span = document.createElement("span");
span.innerHTML = counter;
span.id = "amount";
container.appendChild(span);
}
You can pass along the element that was clicked as a parameter of the increaseCounter function and then get the nextElementSibling of that (the span associated with it), grab the innerHTML (current count) of it, then increment it by 1. This will prevent you from having to fetch the elements by id (as mentioned in the answer by clota974, you want your id's to be unique). You were also missing adding the onclick function for the buttons you were creating as well.
References:
https://www.w3schools.com/jsref/prop_element_nextelementsibling.asp
https://www.w3schools.com/jsref/event_onclick.asp
Here's the example code:
function increaseCounter(el) {
/* increment the span associated with this button (nextElementSibling is the span) */
el.nextElementSibling.innerHTML = parseInt(el.nextElementSibling.innerHTML) + 1;
createNewButton();
}
function createNewButton() {
let container = document.getElementsByClassName("container")[0];
let btn = document.createElement("button");
btn.innerHTML = "new button";
btn.onclick = function() {
increaseCounter(this);
};
container.appendChild(btn);
let span = document.createElement("span");
span.innerHTML = 0;
container.appendChild(span);
}
<div class="container">
<button type="button" onClick="increaseCounter(this)">click</button>
<span>0</span>
</div>

How to build a simple JavaScript to-do list with localStorage

I am building a simple JavaScript to-do list with DOM methods and am attempting to implement localStorage for the list items. localStorage appears to function properly when items are both added and removed. However, the word undefined is thrown to the screen before the list items are rendered. Any idea why this is happening? Much appreciated!
JS:
var ul = document.getElementById("myUl");
function add() {
var item = document.getElementById("newItem").value;
var itemTxt = document.createTextNode(item);
var li = document.createElement("li");
var btn = document.createElement("button");
var btnx = document.createTextNode("x");
btn.setAttribute("onclick", "remove()");
btn.appendChild(btnx);
li.appendChild(itemTxt);
li.appendChild(btn);
ul.appendChild(li);
}
function remove() {
var task = this.event.currentTarget.parentNode;
ul.removeChild(task);
}
ul.innerHTML = localStorage["list"];
setInterval(function(){
localStorage["list"] = ul.innerHTML;
}, 1000);
HTML:
<input id="newItem" />
<button onclick="add()">add</button>
<ul id="myUl">New List</ul>
I updated code with comments:
var ul = document.getElementById("myUl");
function add() {
var item = document.getElementById("newItem").value;
var itemTxt = document.createTextNode(item);
var li = document.createElement("li");
var btn = document.createElement("button");
var btnx = document.createTextNode("x");
btn.setAttribute("onclick", "remove()");
btn.appendChild(btnx);
li.appendChild(itemTxt);
li.appendChild(btn);
ul.appendChild(li);
localStorage["list"] = ul.innerHTML // updating localstorage
}
function remove() {
var task = this.event.currentTarget.parentNode;
ul.removeChild(task);
localStorage["list"] = ul.innerHTML // updating localstorage
}
if (localStorage["list"]) { // checking, if there is something in localstorage
ul.innerHTML = localStorage["list"];
}
Demo: https://codepen.io/anon/pen/dQpwpz
NB: It is not a best practice to put html into localStorage, but I believe you know it.

Text input inserting wrong value into list item

Here is my code: http://jsfiddle.net/H5bRH/
Every time I click on the submit button, it should insert what I typed into a new li item.
But instead of that, it inserts what I typed the first time PLUS the new value that I typed. Play with my jsfiddle to see what I mean.
How do I fix this so that it only adds what the user inputs into the form?
I assume there's something wrong here:
function saveTweet() {
var tweet = document.getElementById("tweet");
var tweetName = tweet.value;
var li = document.createElement("li");
li.innerHTML = tweetName;
var ul = document.getElementById("tweets");
ul.appendChild(li);
}
You have attached 2 click event to save button.
button.onclick = saveTweet;
Using jQuery $("#saveTweet").click(function ()
$("#saveTweet").click(function () {
var tweet = document.getElementById("tweet");
var tweetName = tweet.value;
var li = document.createElement("li");
li.innerHTML = tweetName;
var ul = document.getElementById("tweets");
ul.appendChild(li);
$("li").slideDown("fast");
});
JSFiddle
Why not just reduce all that code to :
$("#saveTweet").click(function () {
$('#tweets').append('<li>' + $("#tweet").val() + '</li>')
$("li").slideDown("fast");
});
jsFiddle example
Instead of having two click handlers for the #saveTweet button, move the slideDown call to your saveTweet function.
function saveTweet() {
var tweet = document.getElementById("tweet");
var tweetName = tweet.value;
var li = document.createElement("li");
li.innerHTML = tweetName;
var ul = document.getElementById("tweets");
ul.appendChild(li);
$("li").slideDown("fast");
}
It happens because you bind two click handlers on the #saveTweet element.
One to add the content, and one to animate the li elements..
In your case the animated one is occuring first and the appending second.. so you always animate the previously added element...
Since you use jQuery anyway, why not use that for all your interactions ?
$(function () {
var button = $("#saveTweet");
button.on('click', function () {
var tweet = $("#tweet"),
ul = $("#tweets"),
tweetName = tweet.val(),
li = $('<li>', {html: tweetName});
ul.append(li);
li.slideDown("fast");
});
});
Demo at http://jsfiddle.net/gaby/Y9cY3/1/

Categories

Resources