Loop array until matches the value of the item clicked - javascript

I'm trying to loop through an array until it matches the value of the object that is clicked.
When the object is created the text input box shares it's value with the object and the array. I would like to be able to loop through the array until there is a match, then find the index, after that pass the index value to a variable to be used. From there remove the object that is clicked from the webpage and the array.
Additional details are that there is an input box with a button. The user enters a line of information into the input box and selects a button to appendChild it to the list. The object created is a div with the input value as the paragraph with a span element with an X which is supposed to remove the object when clicked.
Here is the HTML Code being used
<div id="outerDiv">
<div id="taskList">
</div>
</div>
Here is the code to create the object.
var magicArray = [];
function makeOutline() {
var textValue = document.getElementById("inputBox").value;
if (textValue == "" || textValue == null){
alert("Please enter a item you want to add to the to-do list");
} else {
var inputField = document.getElementById("taskList");
var inputText = document.createTextNode(textValue);
var mainHeading = document.createElement("p");
mainHeading.setAttribute("class", "outlineBorder");
var spanText = document.createTextNode("x");
var spanBox = document.createElement("span");
spanBox.setAttribute("class", "close");
spanBox.setAttribute("onclick", "removeMe()");
var outlineList = document.createElement("div");
outlineList.setAttribute("value", textValue);
spanBox.appendChild(spanText);
mainHeading.appendChild(inputText);
mainHeading.appendChild(spanBox);
outlineList.appendChild(mainHeading);
inputField.appendChild(outlineList);
magicArray[magicArray.length] = textValue;
document.getElementById("inputBox").value = "";
}
}
Here is the code to remove the item.
I am able to have it set to a static number and work every time; however,
struggling to find a dynamic solution since there can be multiple objects.
function removeMe() {
var removeList = document.getElementById("taskList");
removeList.removeChild(removeList.childNodes[1];
}
Here is a screenshot of the family tree structure

First, you can use this to get the element. docs:
When the event handler is invoked, the this keyword inside the handler is set to the DOM element on which the handler is registered.
function removeMe()
{
// this refers to the item that invoked removeMe()
var removeList = document.getElementById("taskList");
removeList.removeChild(this.parentNode.parentNode);
}
Also, this is how you properly add event listeners
spanBox.addEventListener("click", removeMe);
Here is a working jsfiddle for you

Related

onClick Add to Grid from an Array but duplicates on second iteration

Use case is to create Add/show/select/delete text messages on a page. I have used array to store the messages on each click till here it works fine but when I try to create Divs and show the messages in grid, I am having duplication on each click. I can see that my function is reading the array fine and creating the div's on the first click but it does not clear the previously created div on second iteration. Not sure how to approach this. Please advise.
here is the snippet.
<script>
//<!-- Fetch data from Textarea when user Click Save and create or push in an array -->
let ArrNotes = [];
function SaveNote() {
let edittext = document.getElementById("editor").value;
ArrNotes.push(edittext);
document.getElementById("SavedNote").innerHTML = ArrNotes;
let container = document.getElementById("GridNotes");
container.className= "GridNotes";
ArrNotes.forEach(createGrid);
function createGrid(item,index)
{
text = undefined;
var tag = document.createElement("div");
tag.className= "grid";
var text = document.createTextNode(index + ": " + item);
//tag.appendChild(text);
container.appendChild(text);
}
}

Create multiple elements and delete a single one JavaScript

I'm working on a JavaScript project where a user can click a button to create a text element. However, I also want a feature where I can click a different button and the element that was created most recently will be removed, so In other words, I want to be able to click a button to create an element and click a different button to undo that action.
The problem I was having was that I created the element, then I would remove the element using:
element.parentNode.removeChild(element); , but it would clear all of the elements that were created under the same variable.
var elem = document.createElement("div");
elem.innerText = "Text";
document.body.appendChild(elem);
This code allows an element to be created with a button click. All elemente that would be created are under the "elem" variable. so when I remove the element "elem", all element are cleared.
Is there a simple way to remove on element at a time that were all created procedurally?
Thanks for any help
When you create the elements, give the a class. When you want to remove an element, just get the last element by the className and remove it.
The below snippet demonstrates it -
for(let i = 0; i<5; i++){
var elem = document.createElement("div");
elem.innerText = "Text " + i;
elem.className = "added";
document.body.appendChild(elem);
}
setTimeout(function(){
var allDivs = document.getElementsByClassName("added");
var lastDiv = allDivs.length-1;
document.body.removeChild(allDivs[lastDiv]);
}, 3000);
I would probably use querySelectors to grab the last element:
// optional
// this is not needed it's just a random string added as
// content so we can see that the last one is removed
function uid() {
return Math.random().toString(36).slice(2);
}
document.querySelector('#add')
.addEventListener('click', (e) => {
const elem = document.createElement('div');
elem.textContent = `Text #${uid()}`;
document.querySelector('#container').appendChild(elem);
// optional - if there are elements to remove,
// enable the undo button
document.querySelector('#undo').removeAttribute('disabled');
});
document.querySelector('#undo')
.addEventListener('click', (e) => {
// grab the last child and remove
document.querySelector('#container > div:last-child').remove();
// optional - if there are no more divs we disable the undo button
if (document.querySelectorAll('#container > div').length === 0) {
document.querySelector('#undo').setAttribute('disabled', '');
}
});
<button id="add">Add</button>
<button id="undo" disabled>Undo</button>
<div id="container"></div>

how to remove selected list element, instead of removing only top li tag

I'm trying to remove specific li elements, based off of which one has the x button clicked. Currently I'm having an error
"bZMQWNZvyQeA:42 Uncaught TypeError: Failed to execute 'removeChild' on 'Node': parameter 1 is not of type 'Node'."
I am aware that this could mean that the paramater is null, but this dosn't make any sense to me. Chrome dev tools show that the onClick attribute is correctly exectuing removeItem, and passing in the idName as a parameter. How is this not working?
var note = 0;
function saveInfo() {
var idName = "note" + note;
//assign text from input box to var text, and store in local storage
var input = document.getElementById('input').value;
var text = localStorage.setItem(note, input);
var list = document.createElement("li");
var node = document.createTextNode(input);
var removeBtn = document.createElement("button");
list.setAttribute("id", idName);
removeBtn.setAttribute("onClick", `removeItem(${idName})`);
removeBtn.innerHTML = "X";
list.appendChild(node);
list.appendChild(removeBtn);
document.getElementById("output").appendChild(list);
note += 1;
}
function removeItem(name) {
var parent = document.getElementById("output");
var child = document.getElementById(name);
parent.removeChild(child);
}
In my comment, I suggested that you listen to click event bubbling from the removeBtn. In this case, all you need is to remove the onclick attribute assignment logic from your code, and instead give your removeButton an identifiable property, such as a class. Lets give it a class of delete-button:
var removeBtn = document.createElement("button");
removeBtn.classList.add('delete-button');
removeBtn.type = 'button';
removeBtn.innerHTML = 'X';
Then, you can listen to the click event at the level of #output, which is guaranteed to be present at runtime. When the event is fired, you simply check if the event target has the identifiable property, e.g. the remove-button class in our case:
output.addEventListener('click', function(e) {
// GUARD: Do nothing if click event does not originate from delete button
if (!e.target.matches('.remove-button')) {
return;
}
// Delete parent node
e.target.closest('li').remove();
});
If the click event did not originate from the remove button, we simply return and don't do anything else. Otherwise, we know that the button has been clicked, and we can then use Element.closest(), i.e. .closest('li') to retrieve the closest <li> parent node and delete it.
If you absolutely have to support IE11 (which in turn, does not support Element.closest()), you can also use Node.parentNode to access and delete the <li> element, assuming that your remove button is a direct child of the <li> element:
// Delete parent node
e.target.parentNode.remove();
See proof-of-concept below:
var rows = 10;
var output = document.getElementById('output');
for (var i = 0; i < rows; i++) {
var list = document.createElement('li');
var node = document.createTextNode('Testing. Row #' + i);
var removeBtn = document.createElement("button");
removeBtn.classList.add('remove-button');
removeBtn.type = 'button';
removeBtn.innerHTML = 'X';
list.appendChild(node);
list.appendChild(removeBtn);
output.appendChild(list);
}
output.addEventListener('click', function(e) {
// GUARD: Do nothing if click event does not originate from delete button
if (!e.target.matches('.remove-button')) {
return;
}
e.target.closest('li').remove();
});
<ul id="output"></ul>
The issue is that you have missing quotes around the id that you pass to removeItem:
removeBtn.setAttribute("onClick", `removeItem(${idName})`);
This should be:
removeBtn.setAttribute("onClick", `removeItem('${idName}')`);
Better pattern
It is better practice to bind the click handler without relying on string evaluation of code, and without needing to create dynamic id attribute values:
removeBtn.addEventListener("click", () => removeItem(list));
And then the function removeItem should expect the node itself, not the id:
function removeItem(child) {
child.parentNode.removeChild(child);
}
You can remove the following code:
var idName = "note" + note;
list.setAttribute("id", idName);

Remove and Re-Create Element on event:

I am attempting to remove an entire element and recreate it on an event:
I cannot seem to get this right despite several variations of the same code:
For example on event, I need to remove the element and then recreate the same element. I do not want to remove the text:
This is what I have tried (experimental): The result is inconsistent and the code is repetitive.
function removeCreate(){
var input = document.getElementById('display');
var body = document.getElementsByTagName('body')[0];
if(!!input){
input.parentNode.removeChild(input);
input = document.createElement('input');
input.id = 'display';
input.setAttribute('type',"text");
body.appendChild(input);
} else {
input.parentNode.removeChild(input);
input = document.createElement('input');
input.id = 'display';
input.setAttribute('type',"text");
body.appendChild(input);
}
}
Your reason for removing your input element and re-creating it is quite unclear, but let's say it gets modified somehow and you want to "reset" its state.
When you say "I do not want to remove the text", the most probable thing I understand is that you want to keep the current value that the user has typed into your input.
If this fits your situation, then you could simply hold a "template" of your input element in memory, so that you can clone it when needed and use the clone to replace the one in DOM. When doing so, retrieve first the current input value, and inject it back into the cloned input.
Result:
var inputTemplate = document.createElement('input');
inputTemplate.setAttribute('type', 'text');
function cloneInput() {
var newInput = inputTemplate.cloneNode(true);
newInput.id = 'display';
return newInput;
}
var input = document.getElementById('display');
var body = document.getElementsByTagName('body')[0];
if(!!input){
// First retrieve the current value (what the user has typed / default value)
var value = input.value;
input.parentNode.removeChild(input);
input = cloneInput();
input.value = value; // Re-inject the value.
body.appendChild(input); // Note that this would put your input at the bottom of the page.
} else {
//input.parentNode.removeChild(input); // useless?
input = cloneInput();
body.appendChild(input);
}

Error in IE when looping

Lets clarify my question,
I want to make an element which the element contains 5 fields so I dont want the user should be able to put in a new element if the old one is null, so I made the alert when looping through the old element and see if there is some strings, if not then dont put a new element and make an alert please fill out all fields
Here again my code
function addEvent() {
var ni = document.getElementById('discount'); // Takes the a div named discount
var discountForm = document.getElementById('discountForm'); // Takes the a form named discountForm
var numi = document.getElementById('theValue'); // Takes the a hidden input field named theValue
var num = (document.getElementById("theValue").value -1)+ 2; // Start counting to set the new divs form numbers
numi.value = num;
var divIdName = "my"+num+"Div"; // the new divs will be named
var allDivTags = discountForm.getElementsByTagName('div'); // take all div tags
var numOfDivs = (allDivTags.length -1); // take the number of the old div
var oldDivIdName = document.getElementById(allDivTags[numOfDivs].id); // old div id
var newdiv = document.createElement('div'); //the new div
newdiv.setAttribute("id",divIdName);
newdiv.innerHTML = "Company <select name=\"company[]\"><option value=\"\"></option><option value=\"ZI\">Avis</option><option value=\"ET\">Enterprise</option><option value=\"ZE\">Hertz</option><option value=\"ZD\">Budget</option><option value=\"ZR\">National</option><option value=\"AL\">Alamo</option></select> Discount Type <select name=\"type[]\"><option value=\"CD\">Discount Number</option><option value=\"PC\">Coupon Number</option></select> Code <input name=\"code[]\" type=\"text\"> Title <input name=\"title[]\" type=\"text\"> Remove"; // creating the fileds in the new div
ni.appendChild(newdiv);
for(i=0; i<discountForm.elements.length;i++){ // loop through the divs
if(numOfDivs != i-1){ // if tho old div exist and if the old div fields are empty
if(oldDivIdName.children[i].value.length == 0){
removeElement(divIdName); // then dont put the new one
alert('Please enter all fields');
}
}
}
}
But my problem is that in IE comes out an error children[...].value.length is null or not an object so I trying to figure how to fix it,
I hope its more clearly for you now.
It's very hard to tell from the information you've given us. But my first guess is the following:
for(i=0; i<discountForm.elements.length;i++){
if(numOfDivs != i-1){
if(oldDivIdName.children[i].value.length == 0){
removeElement(divIdName);
alert('Please enter all fields');
}
}
}
Above you're doing:
oldDivIdName.children[i]
But i is defined as the number of elements in the form from what I can see... not the number of children of the oldDivIdName. If there are more elements in the form than there are in oldDivIdName then the value of oldDivIdName.children[i] will be null. And "value" is not defined on null.
It's very hard to tell from the information you've given us. But my first guess is the following:
When you first call this method, allDivTags.length whether is null or negative, and results
not got element:
var oldDivIdName = document.getElementById(allDivTags[numOfDivs].id);

Categories