It is supposed to work like this. After I create an item on my list, it should be marked as done with a line-through after clicked and deleted after the delete button is clicked. All this is fine BUT what I really want is to be able to toggle the item as many times as I want. As you can see when I toggle the item it creates a new delete button instead.
function createListElement() {
var li = document.createElement("li"); // you need to create a node first
li.appendChild(document.createTextNode(input.value)); // then append it to the ul
ul.appendChild(li);
input.value = ""; // clear input after submit
// mark it as done
li.addEventListener("click", function () {
li.classList.toggle("done");
//create delete button
var delete_btn = document.createElement("button");
delete_btn.innerHTML = "Delete";
li.appendChild(delete_btn);
// removes element
delete_btn.addEventListener("click", function () {
li.parentNode.removeChild(li);
});
});
}
I'm adding a codepen so you can take a look at it. Thanks.
Check if there'a already a delete button, and don't add another one if so.
var button = document.getElementById("enter");
var input = document.getElementById("userInput");
var ul = document.querySelector("ul");
// If a button is clicked
button.addEventListener("click", addListAfterClick);
// If input is keypressed
input.addEventListener("keypress", addListAfterKeypress);
function inputLength() {
return input.value.length;
}
// create list and button elements
function createListElement() {
var li = document.createElement("li"); // you need to create a node first
li.appendChild(document.createTextNode(input.value)); // then append it to the ul
ul.appendChild(li);
input.value = ""; // clear input after submit
// mark it as done
li.addEventListener("click", function() {
li.classList.toggle("done");
if (!li.querySelector("button.delete")) {
//create delete button
var delete_btn = document.createElement("button");
delete_btn.innerHTML = "Delete";
delete_btn.classList.add("delete");
li.appendChild(delete_btn);
// removes element
delete_btn.addEventListener("click", function() {
li.parentNode.removeChild(li);
});
}
});
}
function addListAfterClick() {
if (inputLength() > 0) {
createListElement();
}
}
function addListAfterKeypress(event) {
if (inputLength() > 0 && event.key === "Enter") {
createListElement();
}
}
body {
#import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght#300&display=swap');
font-family: 'Plus Jakarta Sans', sans-serif;
}
li {
cursor: pointer;
padding: 5px 0;
}
li>button {
margin-left: 10px;
}
.done {
text-decoration: line-through;
}
<h1>Shopping List</h1>
<p><small>Click item to mark it as <strong>done.</strong></small></p>
<input id="userInput" type="text" placeholder="enter items">
<button id="enter">Enter</button>
<ul>
</ul>
Related
I'm working on a simple todo list app in JavaScript.
I need to add new items from the input field on a list, and have the ability to remove items from the list.
I wrote all the necessary functions for storing values from input field and adding it to a list. However I am not able to make removing elements work.
HTML, CSS and JS are provided. removeItems() function doesn't work.
const enterBtn = document.getElementById('enter');
const input = document.querySelector('input');
const ulList = document.querySelector('ul');
const delBtn = document.querySelector('button');
// Get input from the input field and create a new li itemn in ul list
function inputLength() {
return input.value.length;
}
function addDelButtonsToExistingItems() {
const liItems = document.querySelectorAll('li');
for (let i = 0; i < liItems.length; i++) {
const delBtn = document.createElement('button');
delBtn.appendChild(document.createTextNode('delete'));
liItems[i].appendChild(delBtn);
}
}
// Add delete buttons to already existing items in a document
addDelButtonsToExistingItems();
// to add new items from the input field
function addNewItem() {
if (inputLength() > 0) {
const newLiItem = document.createElement('li');
newLiItem.appendChild(document.createTextNode(input.value));
const delBtn = document.createElement('button');
delBtn.appendChild(document.createTextNode('delete'));
newLiItem.appendChild(delBtn);
ulList.appendChild(newLiItem);
input.value = '';
}
}
/**
* To remove items from the list on delete btn pressed
*/
function removeItems(e) {
if (e.target.tagName === 'BUTTON') {
e.target.classList.toggle('remove');
}
}
/**
* To toggle done class on list items clicked
*/
function toggleDone(e) {
if (e.target.tagName === 'LI') {
e.target.classList.toggle('done');
}
}
// If enter key is pressed
function addOnEnterKeyPressed(e) {
if (e.keyCode === 13) {
addNewItem();
}
}
// To add new items on enter btn clicked
enterBtn.addEventListener('click', addNewItem);
// To add new items on enter key pressed
input.addEventListener('keypress', addOnEnterKeyPressed);
// To toggle the done class
ulList.addEventListener('click', toggleDone);
// To remove the items on del btn click
// ???????
.done{
text-decoration: line-through;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Shipping List</title>
</head>
<body>
<h1>Shopping List</h1>
<h3>Get it done today</h3>
<input type="text" name="input" id="input">
<button id="enter">Enter</button>
<ul>
<li>NoteBook</li>
<li>Pens</li>
<li>Eraser</li>
<li>CMPSC 412 book</li>
</ul>
<script src="script.js"></script>
</body>
</html>
Updated the code a bit to get rid of some of the const and simplified the way the delete button click event target is found.
Mostly, I've added a class delete to the delete buttons, so we can target those specifically without relying on the tag.
I commented the code I changed.
const enterBtn = document.getElementById('enter');
const input = document.querySelector('input');
const ulList = document.querySelector('ul');
// Get input from the input field and create a new li itemn in ul list
function inputLength() {
return input.value.length;
}
function addDelButtonsToExistingItems() {
const liItems = document.querySelectorAll('li');
for (let i = 0; i < liItems.length; i++) {
const delBtn = document.createElement('button');
// Let's add a class so we can target it instead of using a tag name.
delBtn.classList.add('delete');
delBtn.appendChild(document.createTextNode('delete'));
liItems[i].appendChild(delBtn);
}
}
// Add delete buttons to already existing items in a document
addDelButtonsToExistingItems();
// to add new items from the input field
function addNewItem() {
if (inputLength() > 0) {
const newLiItem = document.createElement('li');
newLiItem.appendChild(document.createTextNode(input.value));
const delBtn = document.createElement('button');
// Adding a class again.
delBtn.classList.add('delete');
delBtn.appendChild(document.createTextNode('delete'));
newLiItem.appendChild(delBtn);
ulList.appendChild(newLiItem);
input.value = '';
}
}
/**
* To remove items from the list on delete btn pressed. We will do this looking at the document.
*/
function removeItem(e) {
// Since we are watching the document for a click, we can see if the target of the event has the class "delete" and we can remove its parent li.
if (e.target.classList.contains('delete')) {
e.target.parentNode.remove();
}
}
/**
* To toggle done class on list items clicked
*/
function toggleDone(e) {
if (e.target.tagName === 'LI') {
e.target.classList.toggle('done');
}
}
// If enter key is pressed
function addOnEnterKeyPressed(e) {
if (e.keyCode === 13) {
addNewItem();
}
}
// To add new items on enter btn clicked
enterBtn.addEventListener('click', addNewItem);
// To add new items on enter key pressed
input.addEventListener('keypress', addOnEnterKeyPressed);
// To toggle the done class
ulList.addEventListener('click', toggleDone);
// To remove the items on del btn click. We are targeting the document, since the delete elements can update.
document.addEventListener('click', removeItem);
.done {
text-decoration: line-through;
}
<h1>Shopping List</h1>
<h3>Get it done today</h3>
<input type="text" name="input" id="input">
<button id="enter">Enter</button>
<ul>
<li>NoteBook</li>
<li>Pens</li>
<li>Eraser</li>
<li>CMPSC 412 book</li>
</ul>
I've been attempting to prevent duplicate items from being added to a shopping list I created. I thought the code directly below might do it, but it hasn't been helping. I expected the JS code to access the ul tag and iterate through it's list items so it can compare what's already in the list to what's trying to be added. I'm assuming my issue is with accessing the input. Also, which function should this be done in? The createListElement function or the addListAfterClick function. Please see the code snippet for how the code runs. Thank you in advance!!
var ul = document.getElementById("shoppingcart");
var items = ul.getElementsByTagName("li");
for (var i = 0; i < items.length; i++) {
if (input.value === items[i]); {
alert("already in list");
console.log("already in list");
}
var button = document.getElementById("enter");
var input = document.getElementById("userinput");
var ul = document.querySelector("ul");
var li = document.querySelectorAll("li");
function inputLength() {
return input.value.length; // gets the length of the input value
}
function createListElement() {
var li = document.createElement("li"); // creating a new li tag
li.appendChild(document.createTextNode(input.value)); // adding input value to newly created li tag
li.classList.add("item"); // adds a class called "item" to the newly created li tag
li.addEventListener("click", toggleDone);
/* adds click abilities to new item by referencing the toggleDone function, this allows for a line-through
an item in the list if it's clicked,and will remove the line if the item is clicked again */
ul.appendChild(li); // adds the li tag in the ul tag
input.value = ""; //clears the input box to allow for new inputs
var button = document.createElement("button"); // creates anew button tag
button.appendChild(document.createTextNode("delete")); // creates a new button with the word "delete"
li.append(button); //adds delete button next to each new input in the shopping list
button.onclick = removeParent; // if the delete button is clicked, it references the removeParent function which deletes the an input from the shopping list
}
function removeParent(event) {
event.target.parentNode.remove(); // simply deletes an input from the parent node, which is the ul tag, remember li tags are children of ul tags
}
function toggleDone() {
this.classList.toggle('done'); // references the css ".done" class, which allows for line-through text, the toggle function turns on and off the line through
}
function addListAfterClick() {
if (inputLength() > 0) //if the length of the input is greater than 0..(meaning you have to input a something in order to add to the list)
{
createListElement(); // references createListElement function, which adds a new li tag with the input value and a delete button next to it
}
}
function addListAfterKeyPress(event) {
if (inputLength() > 0 && event.keyCode === 13) // if length of the input is greater than 0 and your press the enter key (13 is the value that represents the enter key)
{
{
createListElement(); // references createListElement function, which adds a new li tag with the input value and a delete button next to it
}
}
}
button.addEventListener("click", addListAfterClick);
input.addEventListener("keypress", addListAfterKeyPress);
<!DOCTYPE html>
<html>
<head>
<title> JavaScript + DOM </title>
</head>
<body>
<h1> Shopping List</h1>
<p id="first"> Get it done today</p>
<input id="userinput" type="text" placeholder="enter items">
<button id="enter">Click Me!</button>
<ul class="list" id="shoppingcart">
<li class="bold red" random="23"> Notebook</li>
</ul>
</body>
</html>
A quick solution is to use a "Set", you can check the duplicity in simple steps. For example:
var mySet = new Set();
mySet.add("foo");
mySet.add("fuu");
mySet.has("foo"); // true
mySet.has("fuu"); // true
mySet.has("faa"); // false
So, you can add a set in your first lines and set the conditional has in addListAfterClick:
function addListAfterClick() {
if (inputLength() > 0 && !mySet.has(input.value))
{
createListElement();
}
}
And add the value when input is done in createListElement:
function createListElement()
{
// code...
ul.appendChild(li);
mySet.add(input.value);
input.value = "";
// code...
}
I want to add a delete button beside each of the items that are to be added.
How to do this properly so the all the functions work?
I have tried the method below as you will see in the code. This seems correct to me but it's not working. This needs to be purely JavaScript`.
var button = document.createElement("BUTTON");
var ul = document.getElementById("list");
var li = document.createElement("li");
function handleAddNewItem() //adds new items and more
{
var item = document.getElementById("input").value;
var ul = document.getElementById("list");
var li = document.createElement("li");
if (item === '') {
alert("Input field can not be empty");
}
else {
button.innerText = "Delete";
li.appendChild(document.createTextNode("- " + item));
ul.appendChild(li);
ul.appendChild(button);
}
document.getElementById("input").value = ""; //clears input
//li.onclick = clearDom;
}//code deletes items by clearDom function
document.body.onkeyup = function (e) //allows items to be added with enter button
{
if (e.keyCode == 13) {
handleAddNewItem();
}
}
function clearDom() {
//e.target.parentElement.removeChild(e.target);//removeChild used
ul.removeChild(li);
ul.removeChild(button);
}
button.addEventListener("click", clearDom);
<body>
<input id="input" placeholder="What needs to be done?">
<button id="add_button" onclick="handleAddNewItem()">ADD</button>
<ul id="list">
</ul>
</body>
<script src="new.js"></script>
</html>
var button = document.createElement("BUTTON");
var ul = document.getElementById("list");
var li = document.createElement("li");
function handleAddNewItem() //adds new items and more
{
var item = document.getElementById("input").value;
var ul = document.getElementById("list");
var li = document.createElement("li");
if (item === '') {
alert("Input field can not be empty");
} else {
button.innerText = "Delete";
li.appendChild(document.createTextNode("- " + item));
ul.appendChild(li);
ul.appendChild(button);
}
document.getElementById("input").value = ""; //clears input
//li.onclick = clearDom;
} //code deletes items by clearDom function
document.body.onkeyup = function(e) //allows items to be added with enter button
{
if (e.keyCode == 13) {
handleAddNewItem();
}
}
function clearDom() {
//e.target.parentElement.removeChild(e.target);//removeChild used
ul.removeChild(li);
ul.removeChild(button);
}
button.addEventListener("click", clearDom);
<input id="input" placeholder="What needs to be done?">
<button id="add_button" onclick="handleAddNewItem()">ADD</button>
<ul id="list">
</ul>
<!-- commented out to reduce errors in the console
<script src="new.js"></script> -->
I am facing this error for now-
"The node to be removed is not a child of this node. at
HTMLButtonElement.clearDom new.js:33:7"
I want to implement the delete button in line with the items listed. so that it deletes the items added one by one separately.
I'd suggest:
function handleAddNewItem() {
/* Move the creation of all variables within the function
in which they're being used: */
const button = document.createElement('button'),
ul = document.getElementById('list'),
li = document.createElement('li'),
item = document.getElementById('input').value;
// here we use String.prototype.trim() to remove leading
// and trailing whitespace from the entered value, to
// prevent a string of white-space (' ') being considered
// valid:
if (item.trim() === '') {
alert("Input field can not be empty");
} else {
button.textContent = "Delete";
// here we again use String.prototype.trim(), this time to
// avoid the creation of a ' task '
// with extraneous white-space:
li.appendChild(document.createTextNode("- " + item.trim()));
// appending the <button> to the <li> instead
// of the <ul> (of which it would be an invalid
// child element anyway):
li.appendChild(button);
ul.appendChild(li);
}
document.getElementById("input").value = ''; //clears input
}
document.body.onkeyup = function(e) //allows items to be added with enter button
{
if (e.keyCode == 13) {
handleAddNewItem();
}
}
// the e - the EventObject - is passed automagically from
// the later use of EventTarget.addEventListener():
function clearDom(e) {
// e.target is the element on which the event that we're
// reacting to was originally fired (the <button>):
const clickedButton = e.target;
// here we use DOM traversal methods to find the closest
// ancestor <li> element, and then use ChildNode.remove()
// to remove it from the DOM:
clickedButton.closest('li').remove();
}
// using event-delegation to catch the
// delete-button clicks:
// first we retrieve the element already on the page which
// will be an ancestor of the appended elements:
document.getElementById('list')
// we then bind the clearDom() function - note the deliberate
// lack of parentheses - as the 'click' event-handler:
.addEventListener('click', clearDom);
function handleAddNewItem() {
/* Creating all variables within the function: */
const button = document.createElement('button'),
ul = document.getElementById('list'),
li = document.createElement('li'),
item = document.getElementById('input').value;
if (item.trim() === '') {
alert("Input field can not be empty");
} else {
button.textContent = "Delete";
li.appendChild(document.createTextNode("- " + item));
li.appendChild(button);
ul.appendChild(li);
}
document.getElementById("input").value = '';
}
document.body.onkeyup = function(e) {
if (e.keyCode == 13) {
handleAddNewItem();
}
}
function clearDom(e) {
const clickedButton = e.target;
clickedButton.closest('li').remove();
}
document.getElementById('list')
.addEventListener('click', clearDom);
<input id="input" placeholder="What needs to be done?">
<button id="add_button" onclick="handleAddNewItem()">ADD</button>
<ul id="list">
</ul>
While this question is already, arguably, already answered, I had a few moments to spare and took advantage of this question to begin learning how to use custom elements. The code, as above, is explained so far as possible using comments in the code itself:
// using an Immediately-Invoked Function
// Expression ('IIFE') to handle the creation of the
// custom element:
(function() {
// creating an HTML <template> element, this could
// instead be placed in, and retrieved from, the DOM:
const template = document.createElement('template');
// using a template literal to create, and format
// the HTML of the created <template> (using a template
// literal allows for new-lines and indentation):
template.innerHTML = `
<style>
*, ::before, ::after {
padding: 0;
margin: 0;
box-sizing: border-box;
}
div.layout {
display: grid;
grid-template-columns: 1fr min-content;
}
div.buttonWrap {
display: flex;
flex-direction: column;
align-items: flex-start;
}
</style>
<div class="layout">
<p></p>
<div class="buttonWrap">
<button>delete</button>
</div>
</div>
`;
// using class syntax:
class TaskItem extends HTMLElement {
// the constructor for the class and, by extension,
// the element that we're defining/creating:
constructor() {
// it seems that super() must be placed as the
// first thing in the constructor function:
super();
// we're holding the contents of the custom
// element in the Shadow DOM, to avoid its
// descendants being affected by CSS in the
// parent page and to prevent JavaScript in
// the document from interacting with the
// contents:
this.attachShadow({
// we want to interact and use elements in
// the Shadow Root, so it must be 'open'
// (although 'closed' is the other valid
// mode-type:
mode: 'open'
});
// here we append the content - not the node
// itself - of the created <template> element
// using Node.cloneNode(), the Boolean true
// means that the descendant elements are also
// cloned and therefore appended:
this.shadowRoot.appendChild(
template.content.cloneNode(true)
);
// for easier reading we cache the shadowRoot
// here (otherwise line-lengths can be a bit
// silly):
const root = this.shadowRoot,
// retrieving the <button> element, which will
// handle the task deletion:
del = root.querySelector('button');
// binding the anonymous function - defined
// using an Arrow function as we don't
// want to change the 'this' in the function -
// as the event-handler for the 'click' event:
del.addEventListener('click', () =>
// here we traverse to the parentNode of
// the 'this', and then use
// parentNode.removeChild() to remove the
// 'this' node:
this.parentNode.removeChild(this));
}
// this callback is executed when the element is
// connected/attached to the DOM:
connectedCallback() {
// we find the Shadow Root:
this.shadowRoot
// find the descendent <p> element:
.querySelector('p')
// and set its text-content to be equal
// to that of the data-task attribute:
.textContent = this.dataset.task;
}
}
// here we define the custom element and its
// class:
window.customElements.define('task-item', TaskItem);
})();
// here we cache a reference to the <button> which will
// cause the addition of new tasks:
const addTask = document.getElementById('add_button'),
// define the function that will handle the
// addition of new tasks:
createTask = () => {
// caching the <input> element:
const taskSource = document.getElementById('input'),
// retrieving and trimming the entered
// <input> value:
task = taskSource.value.trim(),
// creating a new element (custom
// elements are created the same way
// as 'normal' elements):
createdTask = document.createElement('task-item');
// updating the data-task attribute, for
// retrieval/use later when the element
// is added to the DOM:
createdTask.dataset.task = task;
// if we have a task (a zero-length/empty
// string is considered falsey, a string
// with a length greater than zero is
// considered truthy and string with negative
// length is considered impossible (I think),
// and therefore falsey:
if (task) {
// we retrieve the element holding the
// <task-item> elements:
document.getElementById('list')
// and append the created element:
.appendChild(createdTask);
}
// removing the <input> element's value:
taskSource.value = '';
};
// adding createTask() as the event-handler for
// the 'click' event on the <button>:
addTask.addEventListener('click', createTask);
// binding an anonymous function as the handler for
// keyup events on the <body> (binding to a closer
// ancestor would be more sensible in production):
document.body.addEventListener('keyup', (e) => {
// if the e.which is 13 we trust that to be the
// enter key, and then we call createTask()
if (e.which === 13) {
createTask();
}
})
#list {
margin-top: 0.5em;
min-height: 1.5em;
background: transparent radial-gradient(at 0 0, skyblue, lime);
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-gap: 5px;
}
#list:empty::before {
content: 'Add a new task!';
background: transparent linear-gradient(to right, #fffa, #fff0);
padding: 0 0 0 1em;
}
task-item {
border: 2px solid lime;
padding: 0.25em;
background-color: #fff9;
}
<input id="input" class="add_task" placeholder="What needs to be done?">
<button id="add_button" class="add_task">ADD</button>
<div id="list"></div>
JS Fiddle demo.
ChildNode.remove().
Classes.
Constructor.
document.createElement().
document.getElementById().
document.querySelector().
Element.attachShadow().
Event object.
event.target.
EventTarget.addEventListener().
Node.appendChild().
Node.parentNode.
Node.removeChild().
Node.textContent.
super().
Window.customElements.
Not very nice but a solution :)
else {
button.innerText = 'Delete';
li.appendChild(document.createTextNode('- ' + item));
ul.appendChild(li);
let but = button.cloneNode(true); // <-- solution
li.appendChild(but);
// clearDom function
clearDom();
}
And also a function that erases a single entry
function clearDom() {
let buttons = document.querySelectorAll('button:not(#add_button)');
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function (e) {
e.target.parentNode.remove();
}, false);
}
}
let button = document.createElement('button');
let ul = document.getElementById('list');
let li = document.createElement('li');
function handleAddNewItem() {
let item = document.getElementById('input').value;
let ul = document.getElementById('list');
let li = document.createElement('li');
if (item === '') {
alert('Input field can not be empty');
}
else {
button.innerText = 'Delete';
li.appendChild(document.createTextNode('- ' + item));
ul.appendChild(li);
let but = button.cloneNode(true);
li.appendChild(but);
clearDom();
}
document.getElementById('input').value = ''; // clears input
}
function clearDom() {
let buttons = document.querySelectorAll('button:not(#add_button)');
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function (e) {
e.target.parentNode.remove();
}, false);
}
}
document.body.onkeyup = function (e) {
if (e.keyCode === 13) {
handleAddNewItem();
}
};
<input id="input" placeholder="What needs to be done?">
<button id="add_button" onclick="handleAddNewItem()">ADD</button>
<ul id="list"></ul>
I have appended 2 buttons for each li element in my app:
todoLi.appendChild(this.createToggleButton());
todoLi.appendChild(this.createDeleteButton());
Later, I added event listeners to trigger when li is moused over and out
todosUl.addEventListener('mouseover', function(event) {
let elementMousedOver = event.target;
if(elementMousedOver.className == 'todoLi') {
elementMousedOver.lastElementChild.style.display = 'inline';
}
});
todosUl.addEventListener('mouseout', function(event) {
let elementMousedOver = event.target;
if(elementMousedOver.className == 'todoLi') {
elementMousedOver.lastElementChild.style.display = 'none';
}
});
Everything works fine for li element, but when I mouse over the buttons, that are children of the li element, event listeners stop working for some reason if the bottons were not children of li element after all.
How can I make appended children to also trigger its parent's event listener?
Here is my app on github: https://mikestepanov.github.io/
repo with files: https://github.com/mikestepanov/mikestepanov.github.io
Events by default are bubbling up the DOM, therefore the event triggered from the li will trigger the ul as well, the issue is that your if statement will handle only the cases in which the event's target is the ul (className == "todoLi")
var todosUl = document.getElementsByClassName("todo")[0];
todosUl.addEventListener('mouseover', function(event) {
let eOver = event.target;
if(eOver.className == 'todo') {
//for the ul
console.log("I'm handeled from " + eOver.className);
} else if (eOver.className == 'item') {
//for the li
console.log("I'm handeled from " + eOver.className);
}
});
todosUl.addEventListener('mouseout', function(event) {
let eOver = event.target;
if(eOver.className == 'todo') {
//for the ul
console.log("I'm handeled from " + eOver.className);
} else if (eOver.className == 'item') {
//for the li
console.log("I'm handeled from " + eOver.className);
}
});
ul{
padding: 15px;
background: lightblue;
}
li{
background: grey;
padding: 5px 5px;
}
<ul class="todo">
<li class="item">Do it!!</li>
</ul>
The problem here lies with the conditional statement. Simply modify your conditional statement to include the button element and it should work.
todosUl.addEventListener('mouseover', function(event) {
let elementMousedOver = event.target;
if(elementMousedOver.className == 'todoLi' ||
elementMousedOver.tagName === "BUTTON") {
elementMousedOver.lastElementChild.style.display = 'inline';
}
});
I am creating a to do list project in vanilla Javascript and have been trying to figure out how to edit an li item in the list on a double click mouse event. I want to be able to have the original text in the textbox after double clicking and update with the new text after clicking away from the textbox or pressing enter.
This is something I tried to write. Please let me know what I am doing wrong or if there is a better approach to the problem.
editInput function() {
var todosUl = document.querySelector('ul');
todosUl.addEventListener('dblclick', function(event) {
if (event.target.childNodes[0]) {
var originalInput = event.target.childNodes[0];
var editingInput = document.createElement("input");
editingInput.type = 'text';
parent = editingInput.parentNode;
parent.replaceChild(originalInput, editingInput);
}
Please no jQuery!
you can use contenteditabe property of html, and add the property on click to the desired element:
Object.prototype.insertAfter = function (newNode) {
this.parentNode.insertBefore(newNode, this.nextSibling);
};
document.addEventListener('keypress', function(e) {
if(e.currentTarget.activeElement.className === 'content'){
if ((e.keyCode || e.which) == 13) {
var li = document.createElement('li');
var ce = document.createAttribute('contenteditable');
ce.value = "true";
var cl = document.createAttribute('class');
cl.value='content';
li.setAttributeNode(ce);
li.setAttributeNode(cl);
e.currentTarget.activeElement.insertAfter(li);
li.focus();
return false;
}else{
return true;
}
}
});
li {
border: 1px solid #ccc;
}
<ul>
<li contenteditable="true" class="content">
</li>