I'm making a to-do list to help me understand Javascript. I've managed to create a series of <li> elements with text inside. I'd like to delete the <li> elements, when they are clicked. However, at the moment they are unresponsive.
JSFIDDLE: http://jsfiddle.net/tmyie/aYLFL/
HTML:
<input id="input" placeholder="Write here">
<button>Add</button>
<hr>
<ul></ul>
Javascript:
var doc = document, // creates a variable, changing 'document' to the variable 'doc'
list = doc.getElementsByTagName('ul')[0],
li = doc.getElementsByTagName('li')[0],
input = doc.getElementById('input'),
button = doc.getElementsByTagName('button')[0]; // creates a variable called 'button', that gets the first array of all the <button> elements
button.onclick = function () {
var mySubmission = doc.getElementById('input').value; // Get values of the input box and call it 'mySubmission'
var item = doc.createElement('li'); // Creates a <li> element in a variable called 'item'
item.innerHTML = mySubmission; // Inside the created 'item', the inner HTML becomes mySubmission + the class 'remove'
list.appendChild(item); // get <ul>, and add the variable 'item'.
doc.getElementById('input').value = ""; // resets input after submission
};
The remove function:
li.onclick = function () {
li.parentNode.removeChild(li);
};
Excuse the excessive comments, I'm try get a better understanding of Javascript.
You define li to be:
li = doc.getElementsByTagName('li')[0]
But there are no li elements to begin with, so doc.getElementsByTagName('li')[0] returns undefined.
You'll need to move that event handler into the other callback:
list.appendChild(item); // get <ul>, and add the variable 'item'.
item.onclick = function () {
list.removeChild(item);
};
Related
I'm making a to-do list application. I want to delete items by clicking a button attached to the list element, but it only deletes the button and not the entire element. Currently, <li> elements in a <ul> by the following:
function newElement() {
event.preventDefault(); // stop default redirect
var li = document.createElement("li"); // create an <li> element
/* make a text node from the input and put it in the <li> */
var inputValue = document.getElementById("task").value; // retrieve value of text box
var t = document.createTextNode(inputValue); // create a text node of the box value
li.appendChild(t); // put the text node in the single <li>
/* attach a button to the <li> element that deletes it */
var btn = document.createElement("BUTTON"); // Create a <button> element
btn.innerHTML = "X"; // Insert text
btn.className = "button" // add class name for CSS targeting
btn.addEventListener('click', removeItem); // add event listener for item deletion
li.appendChild(btn); // Append <button> to <li>
li.addEventListener('click', checkToggle); // add event listener for a click to toggle a strikethrough
appendItem("list", li); //append the li item to the ul
}
and the function called by the button's listener appears as:
function removeItem() {
this.parentNode.removeChild(this);
}
I want the button to delete the entire <li> node, but it only deletes the button portion of it.
Just looking at this, I think you need to add another parentNode. It seems you are only removing the button right now.
Just move this one step further up the hierarchy
function removeItem() {
this.parentNode.parentNode.removeChild(this.parentNode);
}
Use remove() so you are not dealing withe child element references
function removeItem() {
this.parentNode.remove()
// this.closest('li').remove()
}
or since you have a reference, just delete it
btn.addEventListener('click', function () { li.remove() })
I am dynamically creating li with javascript, I want to add a close button to each li element created dynamically to delete the li element on click of the close button.This is my code so far:
function addNew(){
// get value from input field
var taskName = document.getElementById('task-name').value;
// innerHTML to be inserted inside li
var fullText = taskName + '<span class = "close" onclick =
"addListener(this)">×</span>';
// calling create function from Element object
Element.createNew('li','className','tasks',0,fullText);
}
// remove function
function addListener(e){
e.parentNode.parentNode.removeChild(e.parentNode);
}
The problem is the remove function removes the last li instead of li being clicked.
Here is the JSFiddle of the problem.
store all the list items in an array.
//suppose your list items have a class name 'lists'
//create a global var
var lis = document.getElementsByClassName('lists');
initially it'll be empty,
so in your add method(in which you're appending the new list item to ul,
push the new list item in the lists array.
and in the addEvent(e) method , loop around every element in the lists array
function addEvent(e){
for(var i=0; i<lists.length; i++){
if(lists[i] === e){
//remove the lists element by using lists[i] instead of e
// and remember to pop the lists[i] and resize the lists array
}
}
I started self teaching myself JavaScript a couple of weeks ago and have run into a problem I am unable to solve. The program works by allowing a user to enter a list of names which is saved in an array and also shown on the screen as li elements. The program will then randomly select one of the people entered. My problem occurs when trying to remove a person from the list. I am able to remove them from the HTML but not from the array. I have attempted to use the .splice method as shown below but this only removes the last element in the array. I believe this to be due to indexOf(li.value) not being suitable for this use but do not know what else to try. Any help is much appreciated.
<!DOCTYPE html>
<html>
<head>
<title>Student Randomiser</title>
<link rel="stylesheet" href="custom.css">
</head>
<body>
<h1 id="myHeading">Student Randomiser</h1>
<div class="list">
<p class="description">Add Students:</p>
<input type="text" class="studentName" value="Write Students Here">
<button class="addStudent">Add student</button>
<ul id= "listStudentNames">
</ul>
<button class="randomStudent">Select a random student</button>
</div>
<script src="randomNamePicker.js"></script>
</body>
</html>
const addStudent = document.querySelector('button.addStudent');
const studentName = document.querySelector('input.studentName');
const randomStudent = document.querySelector('button.randomStudent');
const listStudentNames = document.querySelector("ul");
let students = [
]
let number
window.onload=function(){
addStudent.addEventListener('click', addStudentToList);
randomStudent.addEventListener('click', selectRandomStudent);
listStudentNames.addEventListener("click", removeStudent);
}
function addButtons(li){
let remove =document.createElement('button');
remove.className= "removeStudent";
remove.textContent = "Remove Student";
li.appendChild(remove)
}
function removeStudent (){
if (event.target.tagName === "BUTTON") {
let li = event.target.parentNode;
let ul = li.parentNode;
let i = students.indexOf(li.value);
students.splice(i,1);
ul.removeChild(li);
}}
function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
number = Math.floor(Math.random() * (max - min)) + min;
}
function addStudentToList() {
students.push(studentName.value);
var ul = document.getElementById("listStudentNames");
var li = document.createElement("li");
li.appendChild(document.createTextNode(studentName.value));
addButtons(li);
ul.appendChild(li);
studentName.value = "";
}
function selectRandomStudent(){
getRandomIntInclusive(0, students.length);
alert(students[number]);
}
There are a variety of issues with your code, some are programmatic, some are stylistic and some are your logic.
Your main issue is that the only elements that have a value property are form elements. So, when you write:
let i = students.indexOf(li.value);
You have an issue because you set li up to be the parent node of event.target. event.target is the element that initiated the event, in this case a <button> and the parent of the button is <div>, which (again) doesn't have a value property and is not the correct element anyway.
This value is what you are basing your splice on. Instead, you need to get the index position of the li within the list of li elements or the array (they should be the same).
Next, you don't really have a need for an array in this scenario in the first place since all of the student names will be elements within a <ul> element, this means that they can be accessed via a "node list", which is an "array-like" object that supports a length property, is enumerable and indexable. Keeping the <li> element content in a synchronized array doesn't add any value here and makes the overall task more complex that it need be because you are forced to keep the HTML list in sync with the array.
Having said all of this, here's a working example of what you are attempting, with comments inline to explain why my code differs from yours.
// When the DOM is loaded and all elements are accessible...
window.addEventListener("DOMContentLoaded", function(){
// Get references to the DOM elements needed to solve problem
// Using "var" here is perfectly acceptable as their scope will
// be the entire parent function, which is what we want. Get all
// these references just once so we don't have to keep scanning
// the DOM for them each time we want to work with the list. Also,
// name your variables "noun"-like names when they refer to elements
var btnAdd = document.querySelector(".addStudent");
var btnRandom = document.querySelector(".randomStudent");
var list = document.getElementById("listStudentNames");
var student = document.querySelector("input[type='text']");
var output = document.querySelector(".report");
// Set up an empty array to keep the synchronized student list in
var students = [];
// Set up click event handling functions
btnAdd.addEventListener("click", addStudent);
btnRandom.addEventListener("click", getRandomStudent);
function addStudent(){
// Make sure there was valid input
if(student.value.trim() === ""){ return; }
// Create a new <li> element
var li = document.createElement("li");
// Set new element up with a click event handler that will
// cause the current element to be removed from the list
li.addEventListener("click", removeStudent);
// Populate the element with the text from the <input>
// The element gets raw text set with the .textContent property
// while content of form elements is gotten with the "value"
// property
li.textContent = student.value;
// Update the list id's to match the array indexes
sync();
// Add the element to the end of the <ul>'s list elements
list.appendChild(li);
// Add new student to the array:
students.push(student.value);
// Clear value from input
student.value = "";
logResults();
}
function getRandomStudent(){
console.clear();
if(students.length){
// Use the built-in JavaScript Math object to get a random number
// between 0 (inclusive) and 1 (exclusive) then multiply that
// number by the lenght of the <li> node list to get a random
// number between 0 and the amount of elements in the array
var random = Math.floor(Math.random() * list.children.length);
console.log("Random student is: " + list.children[random].textContent);
} else {
console.log("No students to choose from!");
}
}
function removeStudent (evt){
// Re-sync the indexes of the HTML elements to match the array
sync();
// Remove corresponding student from array first...
console.clear();
console.log("Student " + evt.target.id + " about to be removed");
students.splice(+evt.target.id, 1);
// Every event handling function automatically gets a reference
// to the event that triggered the function sent into it. We can
// access that event to get a reference to the actual DOM object
// the caused the event to be triggered with "event.target"
list.removeChild(evt.target);
logResults();
}
// We have to keep the HTML element indexes in sync with the array indexes
function sync(){
// Loop through the HTML elements and give them an id that corresponds
// to the index position of its counterpart in the array.
Array.prototype.forEach.call(list.children, function(el, index){
el.id = index;
});
}
// This is just a function for updating the display to show the contents
// of the array to confirm that it is in sync with the list
function logResults(){
output.innerHTML = "Array now contains: <br>" + students.join("<br>");
}
});
.list, .report { float:left; }
.report { background-color:aliceblue; }
<div class="list">
<input type="text" class="studentName" placeholder="Enter Student Name Here">
<button class="addStudent">Add student to list</button>
<ul id= "listStudentNames">
</ul>
<p class="description">(Click on a student to remove them from the list.)</p>
<button class="randomStudent">Select a random student</button>
</div>
<div class="report"></div>
I am attempting to attach an on click event to dynamically created li tags to call a function which takes one argument. The argument to be passed is whatever string is in each li's value property. Below are snippets of code from my program.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
//this is a sample of the format of data in fileList
{"files":["backups","FilesAndFolders.php"]}
//this data is made usable in the the JS code like so
var extracted = JSON.parse(data);
var fileList = extracted.files;
//the li's are being generated by this code which is called by a main function within the JS script
function pathContents(fileList)
{
var list = $('<ul/>').addClass('files');
$.each(fileList, function (_, file) {
$('<li/>').addClass('file').attr('value', file).text(file).appendTo(list);
});
return list;
}
//after main function gets list back from pathContents() it calls this function
function addOnClickToPathContents(fileList)
{
$('.files').on('click', '.file', function(){
var file = fileList[this.value];
pathBuilder(file);
});
}
<ul class="files">
<li value="backups" class="file">backups</li>
<li value="FilesAndFolders.php" class="file">FilesAndFolders.php</li>
</ul>
The problem with this code is it's assigning the event to the ul rather than to each li. Is there a way to modify it so it assigns the on click event to each child li?
The real problem is that li element has no property called value, this.value will always return 0. Instead, you can use attr() method:
$('.files').on('click', '.file', function(){
var file = $(this).attr("value");
pathBuilder(file);
});
If you want to access the file from your fileList array by using the li index, you can use index() method:
$('.files').on('click', '.file', function(){
var file = fileList[$(this).index()];
pathBuilder(file);
});
I hope this will help.
I have a list in JQuery that's called additionalInfo, which is filled in using this JQuery function:
$('#append').on('click', function () {
//check if the following area is valid before moving on, check the jquery validation library
var text = $('#new-email').val();
var li = '<li>' + text + 'input type="hidden" name="additionalInfo" value="'+text+'"/> </li>';
$('#additional-info-list').append(li);
$('#new-email').val('');
});
The point of the function is not only to store the info in a list that can be used later, but also to render a <li> with the info text in it. Right now I have another button on each <li> that when pressed, makes the li vanish, but I also need to add code to it that completely removes the info text from the additionalInfo list. This is the code I have for that method so far:
$('#removeEmail').on('click', 'li>.remove-btn', function (event){
$(event.currentTarget).closest('li').remove();
});
How can I get the segment of info text out of the li and then remove it from additionalInfo?
You have few problems. First of all when you create the new items, your markup is not correct. You were missing the opening bracket of input tag. Also i changed the code for delete so that it listens for the click event on any item with class remove-btn under the li element. This should delete the item when you click the remove link inside the li.
$(function(){
$('#append').on('click', function () {
var text = $('#new-email').val();
var li = '<li>' + text + '<input type="hidden" name="additionalInfo"
value="'+text+'"/>
<a href="#" class="remove-btn" >remove</a></li>';
$('#additional-info-list').append(li);
$('#new-email').val('');
});
$(document).on('click', 'li>.remove-btn', function (event){
var _this =$(this);
_this.closest('li').remove();
});
});
Here is a working jsfiddle