Using something like getElementById for multiple objects? - javascript

Im currently using the document.getElementById("ID") method to fetch a value from an input area and paste it on a div.
This is working fine, but I would like paste these results in two different divs, meaning that I can't use the getElementById method.
I tried using getElementsByName but for some reason is not working.
Here's my JSFiddle with the working code using GetById. What I would like is to get it to output the elements in both Output areas and not just the first one.
var counter1 = 0; //Prevents user from creating multiple nodes on submit
var limit1 = 8; //Amount of nodes that can be created per input field
document.getElementById('textInput1').addEventListener('keypress', function (e) {
if (e.which === 13) {
e.stopPropagation();
e.preventDefault();
createNode1();
}
});
//CREATES FORMATTED NODE FROM INPUT VALUE
function createNode1(){
if (counter1 == limit1) {
//Do nothing
}
else {
var input = document.getElementById('textInput1').value; //Retrieves input
var newText = document.createElement("li"); //Creates the HTML node
newText.innerHTML = input; //Sets the node's value to whatever is in the input
document.getElementById("Form1").appendChild(newText); //Adds the node to the div
document.getElementById('textInput1').value=""; //Clears text field after submit
counter1++;
}
}
//CLEARS THE FORM IF YOU MADE A MISTAKE
function deleteNode1(){
var node = document.getElementById('Form1');
while (node.hasChildNodes()) {
node.removeChild(node.lastChild);
counter1=0;
}
}

USING IDs:
Try this ... using two calls ...
Output1:
<div id="Form1"></div>
<p>
Output2:
<div id="Form2"></div>
... and ...
var newText1 = document.createElement("li"); //Creates the HTML node
var newText2 = document.createElement("li"); //Creates the HTML node
newText1.innerHTML = input; //Sets the node's value to whatever is in the input
document.getElementById("Form1").appendChild(newText1); //Adds the node to the div
newText2.innerHTML = input; //Sets the node's value to whatever is in the input
document.getElementById("Form2").appendChild(newText2); //Adds the node to the div
Basically, I've created two li elements with the value. Then posted those to id's Form1 and Form2
USING CLASSes:
If you had used classes, you could loop through the getElementsByClassNamees.
Try ...
Output1:
<div id="Form1" class='formtype'></div>
<p>
Output2:
<div id="Form2" class='formtype'></div>
var classlist = document.getElementsByClassName("formtype");
for (var i=0; i<classlist.length; i++) {
var newText = document.createElement("li"); //Creates the HTML node
newText.innerHTML = input; //Sets the node's value to whatever is in the input
classlist[i].appendChild(newText); //Adds the node to the div
}

Related

Creating a dynamic list using javascript

I have created a simple to do list which takes the value of the input and places it in a div and attaches some classes to them, everything works fine but how do I fix the for loop and make it work everytime and adds multiple divs under eachother instead of changing the existing one.
Here's my code:
let dynamicList = document.querySelector("#dynamic-list"),
dynamicDiv = document.createElement("div"),
dynamicClass = document.querySelector(".dynamic"),
circle = document.querySelector(".circle"),
paragraphTest = document.createElement("p"),
circleTest = document.createElement("div");
input.addEventListener("keypress", function(e){
value = input.value
if(e.key == "Enter"){
for(i=0; i<=dynamicList.children.length; i++){
dynamicList.insertBefore(dynamicDiv, dynamicClass.nextSibling)
let sibling = dynamicClass.nextSibling;
sibling.classList.add("dynamic")
sibling.appendChild(circleTest)
circleTest.classList.add("circle")
sibling.appendChild(paragraphTest)
paragraphTest.innerHTML = input.value
}
})
<div id="dynamic-list">
<div class="dynamic"><div class="circle"></div><p class="paragraph">some dummy text/p></div>
</div>
Here's what I mean:
https://imgur.com/a/Zgm48ze
That's what happens when I add text, it works perfectly. But when I add another text it overrides the first one instead of adding another div.
You should use createElement method every time you want to create that element. by just using it once, it will create only one, so if you change its property, you are editing the first element (the only one that has been created already).
so the code should be written like this :
let dynamicList = document.querySelector("#dynamic-list"),
dynamicClass = document.querySelector(".dynamic"),
circle = document.querySelector(".circle");
input.addEventListener("keypress", function(e) {
value = input.value
if (e.key == "Enter") {
const paragraphTest = document.createElement("p"),
dynamicDiv = document.createElement("div"),
circleTest = document.createElement("div");
for (i = 0; i <= dynamicList.children.length; i++) {
dynamicList.insertBefore(dynamicDiv, dynamicClass.nextSibling)
let sibling = dynamicClass.nextSibling;
sibling.classList.add("dynamic")
sibling.appendChild(circleTest)
circleTest.classList.add("circle")
sibling.appendChild(paragraphTest)
paragraphTest.innerHTML = input.value
}
}
})

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>

How do I change the styling of a created list item when a checkbox is checked?

I have a website that takes input and adds the text to a list with a checkbox. I am trying to make a function that crosses off items on a list when the corresponding checkbox is checked. I've been playing around with it for a while and I've noticed that the function only works if I code in the list items into the HTML before hand. The function will not work with list items that have been inputted by the user.
Function to add list items with checkbox:
document.getElementById("add").onclick = function() {
let node = document.createElement("li");
let text = document.getElementById("text").value;
let textNode = document.createTextNode(text);
node.appendChild(textNode);
document.getElementById("list").appendChild(node);
let checkBox = document.createElement("input");
checkBox.type = "checkbox";
checkBox.className = "checkbox";
node.appendChild(checkBox);
}
Function to cross off list items when checkbox is checked:
let checkBoxes = document.getElementsByClassName("checkbox");
for (i = 0; i < checkBoxes.length; i++) {
checkBoxes[i].addEventListener("change", checkIt);
}
function checkIt(e) {
if(e.target.checked == false) {
e.target.parentElement.style.textDecoration = "line-through";
}
else {
e.target.parentElement.style.textDecoration = "none";
}
}
Any help would be appreciated as I'm very new to JavaScript!
It seems like you are running the for-loop that adds the eventListeners just once and after new list items are added, they're not being listened to. The simple solution is to add the eventListener when you create the new checkbox like this:
checkBox.type = "checkbox";
checkBox.className = "checkbox";
checkBox.addEventListener("change", checkIt); // <-- add this
node.appendChild(checkBox);
That way all new checkboxes will have something to do when changed.
You need to add a class to your the element that you want to strike-through on click.
the structure needs to have the checkbox and the text you want to strike through on the same level:
div
checkbox
text
then you can use a css ::after pseudo selector to add animation to the text.
.checkbox:checked ~ .text {
// animation of strikethrough css
}
the ~ selector is a "sibling" selector that will find a checkbox that is checked and run the css on the .text that is placed directly after the checkbox.
Welcome to stackoverflow and javascript world, #TheWolf1494
As I understand, you are trying to bind your event handler function to checkboxes before you create them on DOM, when the document is ready. That means you are binding your function to nowhere.
Please try the following one;
document.getElementById("add").onclick = function () {
// Your existing codes
var node = document.createElement("li");
var text = document.getElementById("text").value;
var textnode = document.createTextNode(text);
node.appendChild(textnode);
document.getElementById("list").appendChild(node);
var checkBox = document.createElement("input");
checkBox.type = "checkbox";
checkBox.className = "checkbox";
// For test purpose
checkBox.id = new Date().toISOString();
// Bind the event handler here
checkBox.onclick = function () {
console.log(this.id + ' is ' + (this.checked ? 'checked' : 'unchecked'))
}
node.appendChild(checkBox);
}

Javascript- Creating To Do list not working

I deleted the button part in my script but not even the first part of my function is working where I type in input box and suppose to be added to the ...I don't understand why. When I run the code without the buttons code which is titled " //BUTTON creation " I get no error but no item is being added to the list. So I have two problems Items aren't being added to my list and aren't displaying and also if I include the button part its saying an error "list.appendChild is not a function"
<input type="text" placeholder="Enter an Activity" id="textItem">
<img src="images/add-button.png" id="addButton">
<div id="container">
<ul class="ToDo">
<!--
<li>
This is an item
<div id="buttons">
<button ></button>
<img src="images/remove-icon.png"id="remove">
<button id="complete"></button>
<img src="images/complete-icon.jpg" id="complete">
</div>
</li>
!-->
</ul>
</div>
<script type="text/javascript">
//Remove and complete icons
var remove = document.createElement('img').src =
"images/remove-icon.png";
var complete = document.createElement('img').src = "images/complete-icon.jpg";
//user clicks add button
//if there is text in the item field we grab the item into var text
document.getElementById("addButton").onclick = function()
{
//value item is the text entered by user
var value = document.getElementById("textItem").value;
//checks if there is a value typed
if(value)
{
addItem(value);
}
//adds a new item to the ToDo list
function addItem(text)
{
var list = document.getElementsByClassName("ToDo");
//created a varibale called item that will create a list item everytime this function is called
var item = document.createElement("li");
//this will add to the innerText of the <li> text
item.innerText = text;
//BUTTON creation
var buttons = document.createElement('div');
buttons.classList.add('buttons');
var remove = document.createElement('buttons');
buttons.classList.add('remove');
remove.innerHTML = remove;
var complete = document.createElement('buttons');
buttons.classList.add('complete');
complete.innerHTML = complete;
buttons.appendChild(remove);
buttons.appendChild(complete);
list.appendChild(buttons);
list.appendChild(item);
}
}
</script>
The problem is in the line:
var list = document.getElementsByClassName("ToDo");
list.appendChild(item);
The line var list = document.getElementsByClassName("ToDo"); will provide a collection, notice the plural name in the api.
You need to access it using :
list[0].appendChild(item);
There are other problems too in the code but hopefully this gets you going!
There are a couple of issues in your code that need to be addressed to get it to work properly.
1) You are creating your image elements and then setting the variables to the src name of that image and not the image object itself. When you use that reference later on, you are only getting the image url and not the element itself. Change var remove = document.createElement('img').src = "images/remove-icon.png" to this:
var removeImg = document.createElement('img')
removeImg.src = "images/remove-icon.png";
2) As #Pankaj Shukla noted, inside the onclick function, getElementsByClassName returns an array, you will need to address the first item of this array to add your elements. Change var list = document.getElementsByClassName("ToDo") to this:
var list = document.getElementsByClassName("ToDo")[0];
3) For your buttons, you are trying to creating them using: var remove = document.createElement('buttons'). This is invalid, buttons is an not the correct element name, its button. Additionally, you are re-declaring the variables remove and complete as button objects, so within the onclick function it reference these buttons, not the images you defined earlier. So when you assign the innerHTML to remove and complete, you are assigning the buttons innerHTML to itself. The solution is to change the image variables to something different.
4) Finally, also relating to the buttons, you are assigning the innnerHTML to an image object, that's incorrect. You can either insert the html text of the img directly, or append the image object as a child of the button, similar to how the button is a child of the div.
The updated code with all these changes looks like this:
//Remove and complete icons
var removeImg = document.createElement('img');
removeImg.src = "images/remove-icon.png";
var completeImg = document.createElement('img');
completeImg.src = "images/complete-icon.jpg";
//user clicks add button
//if there is text in the item field we grab the item into var text
document.getElementById("addButton").onclick = function() {
//value item is the text entered by user
var value = document.getElementById("textItem").value;
//checks if there is a value typed
if (value) {
addItem(value);
}
//adds a new item to the ToDo list
function addItem(text) {
var list = document.getElementsByClassName("ToDo")[0];
//created a varibale called item that will create a list item everytime this function is called
var item = document.createElement("li");
//this will add to the innerText of the <li> text
item.innerText = text;
//BUTTON creation
var buttons = document.createElement('div');
buttons.classList.add('buttons');
var remove = document.createElement('button');
remove.classList.add('remove');
remove.appendChild(removeImg);
var complete = document.createElement('button');
complete.classList.add('complete');
complete.appendChild(completeImg);
buttons.appendChild(remove);
buttons.appendChild(complete);
list.appendChild(buttons);
list.appendChild(item);
}
}

Firebase, finding the key of parent based on child's value

essentially what I am trying to do is to create a button on a created text node in js. Then find the value of spmet and remove the question (spmet) from the database.
However I can't figure out how to properly reference it, and find the specific value that I want deleted. (so other picture, remove that question from database when I press the "x")
this is the the way to remove questions
This is the firebase layout
var btn = document.createElement("BUTTON");
var btnText = document.createTextNode("x"); //create button
btn.appendChild(btnText);
tekst.appendChild(btn);
btn.id = "questionBtn";
//bytter enter som gir linjeskift til <br>
tekst.innerHTML = tekst.innerHTML.replace(/\n/g, '<br>');
chat.appendChild(bubble);
setTimeout(function(){
chat.classList.add('visible')
}, 1);
chat.scrollTop = chat.scrollHeight;
console.log(bubble);
// Function to remove the question on the button generated
tekst.onclick = function removeQ(){
window.alert("Knapp funker");
var ref = database.ref();
ref.child('spm')
.orderByChild('spmet')
.equalTo(spmet)
.once('value', function(snap) {
//remove the specific spmet parent
window.alert(snap.val());
});
document.getElementById("cont1").removeChild(bubble); // removes text from page
var spmRef = ??
spmRef.remove(); //can't reference properly
}
When you generate the HTML element for each question, keep the ID of that question as an attribute on that HTML element:
ref.child("spm").on("child_added", function(snapshot) {
var div = document.createElement("div");
div.id = snapshot.key;
div.innerText = snapshot.child("spmet").val();
div.onclick = onSpmClick;
questionContainer.appendChild(div);
});
Now when the user clicks on one of the questions, you can get the key from that div and remove it:
function onSpmClick(e) {
var key = e.target.id;
ref.child("spm").child(key).remove();
}

Categories

Resources