This question already has answers here:
JavaScript DOM remove element
(4 answers)
Closed 3 years ago.
I am trying to make a simple list using html input box and js. the list are creating on clicking "add skill" and get removed when click on "remove". But when I try to add some skill after remove, the last removed item also get back.
var skillList="";
var i = 0;
function addSkill(){
var skills= document.getElementById("addSkill").value;
if(skills != ""){
skillList += "<li><span name='skillItem' id='skillItem"+ i +"'>" + skills + "</span> " +
"<a onclick='removeSkill()'>remove</a></li>";
i++;
document.getElementById("skill").innerHTML = skillList;
document.getElementById("addSkill").value="";
}
}
function removeSkill(){
skillList="";
var items = document.querySelectorAll("#skill li"),index,tab = [];
for(var j = 0; j < items.length; j++){
tab.push(items[j].innerHTML);
}
for(var j = 0; j < items.length; j++){
items[j].onclick = function(){
index = tab.indexOf(this.innerHTML);
items[index].parentNode.removeChild(items[index]);
tab.splice(j,1);
};
}
console.log(tab);
for(var j=0; j<tab.length;j++){
skillList += "<li>" + tab[j] + "</li>";
}
}
<td><label>skills:</label></td>
<td>
<ul id="skill"></ul>
<input type="text" name="skill" id="addSkill"/>
<a onclick="addSkill();" value="">add skill</a>
</td>
Just delete this piece of code
for(var j=0; j<tab.length;j++){
skillList += "<li>" + tab[j] + "</li>";
}
Your were adding it again...
Working now...
var skillList="";
var i = 0;
function addSkill(){
var skills= document.getElementById("addSkill").value;
if(skills != ""){
skillList += "<li><span name='skillItem' id='skillItem"+ i +"'>" + skills + "</span> " +
"<a onclick='removeSkill()'>remove</a></li>";
i++;
document.getElementById("skill").innerHTML = skillList;
document.getElementById("addSkill").value="";
}
}
function removeSkill(){
skillList="";
var items = document.querySelectorAll("#skill li"),index,tab = [];
for(var j = 0; j < items.length; j++){
tab.push(items[j].innerHTML);
}
for(var j = 0; j < items.length; j++){
items[j].onclick = function(){
index = tab.indexOf(this.innerHTML);
items[index].parentNode.removeChild(items[index]);
tab.pop(j,1);
};
}
}
<td><label>skills:</label></td>
<td>
<ul id="skill"></ul>
<input type="text" name="skill" id="addSkill"/>
<a onclick="addSkill();" value="">add skill</a>
</td>
You got all lost in the loops and indexes in your removeSkill function and it's way easier than what you are doing - one single line of code. No loops and no arrays are needed.
You've also got a bunch of other styles of coding that are ancient and should be avoided.
You don't need to use a hyperlink just because you want to give
someone something to click on. All visible elements support a click
event. Only use hyperlinks when you are actually navigating
somewhere.
You can't use table cells without a table.
Don't use inline HTML event attributes (onclick). Separate all your
JavaScript from your HTML and do the event binding with
.addEventListener().
Don't create new HTML by concatenating strings together. It becomes a
nightmare fast and requires you to use .innerHTML, which has
performance and security implications. Instead, create new DOM
objects, configure their properties as needed and then append them
into the document.
See the comments inline below:
// Get all the element references you'll need just once:
var skillList = document.querySelector("#skillList");
var newSkill = document.querySelector("#newSkill");
var btnAddSkill = document.querySelector("input[type='button'");
// Do all of your event binding in JavaScript, not with inline HTML event attributes
btnAddSkill.addEventListener("click", addSkill);
function addSkill(){
if(newSkill.value !== ""){
// Don't build new HTML by concatenating strings. Create elements and configure them as objects
var li = document.createElement("li");
li.textContent = newSkill.value;
// Only use hyperlinks for navigation, not to have something to click on. Any element can be clicked
var span = document.createElement("span");
span.classList.add("remove");
span.textContent = "remove skill";
span.addEventListener("click", removeSkill);
li.appendChild(span); // Add the span to the bullet
skillList.appendChild(li); // Add the bullet to the list
newSkill.value = "";
}
}
function removeSkill(){
// Just remove the closest <li> ancestor to the <span> that got clicked
skillList.removeChild(this.closest("li"));
}
.remove { display:inline-block; margin-left:10px; padding:2px 4px; background:rgba(200,0,225,.7); color:#ff0; cursor:pointer; }
li {margin:8px 0; border-bottom:1px dashed #e0e0e0; }
<h1>Skills:</h1>
<input type="text" name="skill" id="newSkill">
<input type="button" value="add skill">
<ul id="skillList"></ul>
Related
I have very little experience with Javascript.
My goal is to build a table from an array, and allow the user to delete items from the array as needed. I wanted to have a "delete" button next to each array item that is shown.
I'm open to other ideas of how to accomplish this. My code is here:
var LargeList = ["¥"]
function AddLargeItem() {
LargeList.push(document.getElementById("LargeItems").value)
LLen = LargeList.length;
text = "<ol>";
for (i = 0; i < LLen; i++) {
text += "<li>" + LargeList[i] + "</li>";
}
text += "</ol>";
document.getElementById("LargeInventory").innerHTML = text;
document.getElementById("LargeCount").innerHTML = LLen * 10;
document.getElementById("random").innerHTML = LargeList.join("/ ");
}
The target HTML:
<body>
<div>
<select id="LargeItems">
<option></option>
<option>LMIS</option>
<option>ARMC</option>
<option>BNCH</option>
</select>
<input type="button" onclick="AddLargeItem()" id="AddLargeItem" value="ADD LARGE" />
<span><p id="LargeCount"></p></span>
</div>
<p id="random"></p>
<p id="LargeInventory"></p>
</div>
I wanted to have a "delete" button next to each array item that is shown
To achieve your above requirement, you can modify the code as below.
<script>
var LargeList = ["¥"]
function AddLargeItem() {
LargeList.push(document.getElementById("LargeItems").value)
PopulateList(LargeList);
}
function PopulateList(arr) {
LLen = arr.length;
text = "<ol>";
for (i = 0; i < LLen; i++) {
text += "<li>" + arr[i] + "<input type='button' onclick='Delitem(" + i + ")' value='Delete' /></li>";
}
text += "</ol>";
document.getElementById("LargeInventory").innerHTML = text;
document.getElementById("LargeCount").innerHTML = LLen * 10;
document.getElementById("random").innerHTML = arr.join("/ ");
}
function Delitem(index) {
LargeList.splice(index, 1);
PopulateList(LargeList);
}
</script>
Test Result
There is two ways I can think of to do this.
num one:
assign the elements you want to delete and id ex: then use javascript to append the elements with your list. then onclick="remove('list')" and make a function like this
function remove(id){getElementById(id).remove()}
num two:
if you just want to use javascript def your list then get an integer from the user and use my something like this
index = getElementById('foo').value;
my_list = my_list[:foo] + my_list[foo+1:];
document.write(my_list);
I am trying to understand the insertion sort algorithm. I want to use an input button and diagram. When the user writes a number then click the button, my page will create random values. I found some snippets on the internet but they use i = 0. I want to use my input value instead of i = 0. How can I do it?
A part of my index.html:
<div id="buttons">
<a class="button" id="butonInsert" href="javascript://">insertion sort</a>
<a class="button" id="butonReset" href="javascript://">Reset</a>
<input type="number" id="myNumber" value="blabla">
<button onclick="reset()"></button>
A part of my script.js:
function reset() {
for (i=0; i<50; ++i) {
data[i] = ~~(i*160/50);
}
for (i=data.length-1; i>=0; --i) {
var ridx = ~~( Math.random() * ( data.length ) );
data.swap(i, ridx);
}
var tb = $("#sortPanel");
tb.empty();
var tr = $("<tr></tr>");
for (i=0; i<data.length; ++i) {
tr.append("<td id='b"+i+"'>" +
"<div class='cc' style='height: "+data[i]+"px;'>" +
"</div></td>");
}
tb.append(tr);
resetted = true;
}
I didn't quite understand what you are trying to do but if you just want to use an input's value you can easily get it with javascript and use it instead of i=0.
var inputValue = document.getElementById("myNumber").value ;
Then in your for statements :
for (var i = inputValue ; i < data.length; ++i) {
// code
}
Use document.getElementbyId('myNumber').value. This might work.
Alright so I hope Im just missing something easy. Basically I am making a todo list where I want to have a checkbox appear with each list item (this works). When users click on the checkbox, the textDecoration = "line-through" is supposed to go through the listItem class. Meaning a line goes through the todo task the person creates. Here is the code I am mainly working with:
function show() {
var todos = get_todos();
var html = '<ul>';
for(var i=0; i < todos.length; i++) {
html += '<span><li class="listItem" style="float:left;">' + todos[i] + '</li><input class="checkBox" type="checkbox">' + '<button class="remove" id="' + i + '"><i class="fa fa-trash" aria-hidden="true"></i></button></span><br/>';
};
html += '</ul>';
document.getElementById('todos').innerHTML = html;
var buttons = document.getElementsByClassName('remove');
for (var i=0; i < buttons.length; i++) {
buttons[i].addEventListener('click', remove);
};
////////////////////////////////////
//Everything above here works. Below is the checkbox issue
var checkBox = document.getElementsByClassName("checkBox");
var listItem = document.getElementsByClassName("listItem");
for (var i=0; i < checkBox.length; i++) {
if (checkBox.checked == true){
listItem.style.textDecoration = "line-through";
}else {
listItem.style.textDecoration = "none";
}
};}
Where I'm at now is if I create an onClick function in the original checkbox, I can use that if/else statement and it kind of works. It will not work if I set the checkBox/listItems variables using document.getElementsByClassName but it will work if I use document.getElementById. The problem is that it only works on the first task that the user creates and none of the other ones created after. Im assuming that is either because Ids only work for one element (unlike a class that works for multiple) or because its not cycling through a for loop like it is in the code above.
TL/DR Basically when I run the code above I keep getting "Uncaught TypeError: Cannot set property 'textDecoration' of undefined
at show (todo.js:57)
at todo.js:75".
I dont get this error when I make a separate function for the checkbox and use elementbyid instead of elementsbyclass (changing the id/class of the html section above too)
I really want to get those line-through effects working on all tasks, not just the first one. Any ideas are greatly appreciated. Thanks everyone!
I would accomplish this with css instead of javascript (that's generally my rule, when possible). In this case you have to make one small change to your markup: since there's no previous-sibling selector, you'll have to put the inputs before the corresponding lis, but since the lis are float:left it still renders exactly the same.
input:checked + li {
text-decoration:line-through;
}
<ul>
<span><input class="checkBox" type="checkbox"><li class="listItem" style="float:left;">foo</li><button class="remove" id="' + i + '"><i class="fa fa-trash" aria-hidden="true"></i></button></span><br/>
<span><input class="checkBox" type="checkbox"><li class="listItem" style="float:left;">bar</li><button class="remove" id="' + i + '"><i class="fa fa-trash" aria-hidden="true"></i></button></span><br/>
<span><input class="checkBox" type="checkbox"><li class="listItem" style="float:left;">baz</li><button class="remove" id="' + i + '"><i class="fa fa-trash" aria-hidden="true"></i></button></span><br/>
</ul>
function show() {
var todos = get_todos();
var html = '<ul>';
for (var i = 0; i < todos.length; i++) {
html += '<span><li class="listItem" style="float:left;">' + todos[i] + '</li><input class="checkBox" type="checkbox">' + '<button class="remove" id="' + i + '"><i class="fa fa-trash" aria-hidden="true"></i></button></span><br/>';
};
html += '</ul>';
document.getElementById('todos').innerHTML = html;
var buttons = document.getElementsByClassName('remove');
for (var i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', remove);
};
////////////////////////////////////
//Everything above here works. Below is the checkbox issue
var checkBox = document.getElementsByClassName("checkBox");
var listItem = document.getElementsByClassName("listItem");
for (var i = 0; i < checkBox.length; i++) {
if (checkBox[i].checked == true) {
listItem[i].style.textDecoration = "line-through";
} else {
listItem[i].style.textDecoration = "none";
}
};
}
You probably missed the index in the listItem and checkBox array
I think the problem is that checkBox is an array-like object. I think you know that as when you wrote the code you look at checkBox.length, however you then failed to index into the array.
You have:
var checkBox = document.getElementsByClassName("checkBox");
var listItem = document.getElementsByClassName("listItem");
for (var i=0; i < checkBox.length; i++) {
if (checkBox.checked == true){
listItem.style.textDecoration = "line-through";
}else {
listItem.style.textDecoration = "none";
}
};}
To make it clear I've pluralised the names where needed, as well as adding the index reference:
var checkBoxes = document.getElementsByClassName("checkBox");
var listItems = document.getElementsByClassName("listItem");
for (var i=0; i < checkBoxes.length; i++) {
if (checkBoxes[i].checked == true){
listItems[i].style.textDecoration = "line-through";
}else {
listItems[i].style.textDecoration = "none";
}
};}
I started creating some minor code within my site, and i wanted to do some dynamic creation, so some span tags are created using a javaScript for loop.
In the same code, but a different loop i want to add an Event Listener to the tags.The error i get is the element created is non existent, and i have a few ideas why it's not working, but searching the Web and Stack Overflow gave me no answers.
I've considered putting both for loops into a function and calling that function in a similar fashion jquery works with it's document ready function. But i don't think that will fix the issue
var country = ["is_AmericaN", "is_Europe",
"is_Africa","is_AmericaS","is_Asia","is_Australia"];
var spanInto = document.getElementById("spanSelect");
for(i=0; i<6; i++)
{
var spanMake = document.createElement("SPAN");
spanInto.appendChild(spanMake);
spanMake.className += "spanLanguage" + " " + country[i];
}
The code above creates the elements, the code below tries to call them
var countryClass = doucment.getElementsByClassName("spanLanguage");
for(i=0; i< document.countryClass.length; i++)
{
countryClass[i].addEventListener("click", function(){
var hrDisplay = document.getElementById("selectiveDisplay");
hrDisplay.removeAttribute("id");
hrDisplay.className = "noDisplay";
},false);
}
I expect the working code to, once clicked on any span tag, set the display of the hr tag to block or flex. I dont want to create 5-6 span tags manually, it has to be a dynamic creation.
You are missing the position of the adding class
var spanMake = document.createElement("SPAN");
spanInto.appendChild(spanMake);
spanMake.className += "spanLanguage" + " " + country[i];
Here you are assigning the class after appending it into span, that is wrong you need to assign class before.
var countryClass = doucment.getElementsByClassName("spanLanguage");
for(i=0; i< document.countryClass.length; i++)
{
doucment is document and document.countryClass should be countryClass as you already have the instance of the element
var country = ["is_AmericaN", "is_Europe",
"is_Africa", "is_AmericaS", "is_Asia", "is_Australia"
];
var spanInto = document.getElementById("spanSelect");
for (i = 0; i < 6; i++) {
var spanMake = document.createElement("SPAN");
spanMake.textContent = country[i];
spanMake.className += "spanLanguage" + " " + country[i];
spanInto.appendChild(spanMake);
}
var countryClass = document.getElementsByClassName("spanLanguage");
for (i = 0; i < countryClass.length; i++) {
countryClass[i].addEventListener("click", function() {
var hrDisplay = this;
hrDisplay.removeAttribute("id");
hrDisplay.className = "noDisplay";
}, false);
}
.noDisplay {
display: none;
}
<span id="spanSelect"></span>
<br/>
//click on any of them to replace the class
There are multiple points to be corrected:
There was a type "doucment" in your code.Use "document" instead.
Created elements didn't have any text on it, how will you call click
on element when it is not visible in DOM.
Events are attached to anchors/button not span.
Not sure what you are trying to do by attaching events.
below is the code snippet which works for you when you try to add events on dynamic created elements.Let me know if you need further help
function temp() {
var country = ["is_AmericaN", "is_Europe",
"is_Africa", "is_AmericaS", "is_Asia", "is_Australia"
];
var spanInto = document.getElementById("spanSelect");
for (i = 0; i < 6; i++) {
var spanMake = document.createElement("a");
spanMake.innerHTML = country[i];
spanInto.appendChild(spanMake);
spanMake.className += "spanLanguage" + " " + country[i];
}
}
function attachEvent() {
var countryClass = document.getElementsByClassName("spanLanguage");
for (i = 0; i < countryClass.length; i++) {
countryClass[i].addEventListener("click", function(event) {
console.log("I am called" + event.target);
//var hrDisplay = document.getElementById("selectiveDisplay");
//hrDisplay.removeAttribute("id");
//hrDisplay.className = "noDisplay";
}, false);
}
}
a {
padding: 20px;
}
<body>
<div id="spanSelect"></div>
<div id="selectiveDisplay"> </div>
<button onclick="temp()"> Call Me </button>
<button onclick="attachEvent()"> Attach Event </button>
</body>
Beginner here. I have a loop that creates 26 buttons with unique ID's and values. What I'm struggling with is figuring out the proper way to send the button's ID to a function so that I can store unique vars for each button independently without creating more than one function. I currently have an array with the 26 items I need for my buttons and the following loop:
function makeButtons() {
for (var i = 0; i < 26; i++) {
document.getElementById("whereButtonsGo").innerHTML += "<input type = 'button' value = '" + items[i] + "' id = 'button" + items[i] + "' onclick = doThing(button" + items[i] + ")'>";
}
}
I want the argument in the onclick function to be sent to a function such as:
function doThing(id) {
document.getElementById("'" + id.value + "'").style.color = "pink";
}
But so far I haven't been able to get this to work. Any help would be greatly appreciated!
Maybe this is what you are looking for:
makeButtons();
function makeButtons() {
for (var i = 0; i < 26; i++) {
document.getElementById("whereButtonsGo").innerHTML += "<input type = 'button' value = '" + i + "' onclick = doThing(this)>";
}
}
function doThing(currentButton) {
currentButton.style.color = "pink";
}
<div id="whereButtonsGo"/>
Try to keep the IDs as simple as possible
I recommend against using innerHTML for creating elements that you actually want to do something. Even if it works, your code will be amazingly unclear. Instead, write code that demonstrates that you're actually creating and adding elements:
var items = [1,2,3,4,5,6];
function makeButtons() {
var container = document.getElementById("whereButtonsGo");
for (var i = 0; i < items.length; i++) {
var button = document.createElement("button");
button.type = 'button';
button.value = items[i];
button.innerText = items[i];
button.id = 'button'+items[i];
button.onclick = doThing;
container.append(button)
}
}
function doThing() {
console.log('click of ' + this.id);
}
makeButtons();
Note that you don't need to pass the id in the function call for the event - the button that was clicked will be available as this.
Here is a fiddle.