I created a To-Do List with JS. I'm mostly finished but my last task is to create a local storage. The purpose of that is, that the Tasks should not vanish, when I reload the page. I know that I have to create an array of objects for that, but I don't know how to represent my <'li'> element as an object. So how do I represent my Tasks as an object to create an array
add.addEventListener("click", function (){
// create task text
if(task.value != ""){
let li = document.createElement('li');
ul.appendChild(li);
// create checkbox
let box = document.createElement('input');
box.setAttribute('type', 'checkbox');
li.appendChild(box);
box.classList.add('check');
//create span
let span = document.createElement('span');
li.appendChild(span);
span.innerHTML= task.value;
span.classList.add('task');
// create delete button
let btn = document.createElement('button');
li.appendChild(btn);
btn.classList.add("delete-btn");
btn.innerHTML = 'x';
btn.onclick = function () {
btn.parentElement.remove();
};
});
Related
I'm trying to make my basic to do list better and I want to be able to delete a task when a button is clicked. How can I go about doing this? I've given the button dynamic ID's but cant seem to find out how to return that specific ID when a specific button is clicked.
Javascript
let Task = [];
function addTask(){
//assign input to array
var task = document.getElementById("userInput").value;
Task.push(task);
//creates node and shows where to find value
let node = document.createElement("li");
let textNode = document.createTextNode(
document.getElementById("userInput").value
);
//create button for text node to delete
const btn = document.createElement('button');
btn.innerHTML = 'Delete';
//adds task to webpage
node.appendChild(textNode);
document.getElementById("myList").appendChild(node);
//Adds button to webpage, gives button dynamic ID
document.getElementById("myList").appendChild(btn).id = Task.length;
}
If I understand correctly what you want is to assign a dynamic ID and return that ID by clicking the button, correct?
In this case you can try something like:
// Adds button to webpage, gives button dynamic ID
document.getElementById("myList").appendChild(btn);
btn.setAttribute("id", "myCustomId");
document.getElementById("myList").appendChild(btn);
btn.setAttribute("onclick", "alert('Current button ID: '+this.id)");
I am looking to add draggable functionality to my todo list project,
I am trying to use a forEach loop to loop over my elements and for now just change the opacity of each div when dragged. However I can not find a way for this to work on elements which I have created, the draggable attribute is added but they dont work with the loop.
function addTodo() {
const todoDiv = document.createElement('div')
todoDiv.classList.add('todo')
const newButton = document.createElement('button');
newButton.classList.add('todo-button')
const newLine = document.createElement('div')
newLine.classList.add('line')
const newTodo = document.createElement('li');
newTodo.innerText = todoInput.value
newTodo.classList.add('todo-text')
const newDelete = document.createElement('button');
newDelete.innerHTML = '<i class="fas fa-times "></i>'
newDelete.classList.add('delete-todo')
todoList.appendChild(todoDiv)
todoDiv.appendChild(newButton)
todoDiv.appendChild(newLine)
newLine.appendChild(newTodo)
newLine.appendChild(newDelete)
var att = document.createAttribute("draggable");
att.value = "true";
todoDiv.setAttributeNode(att);
}
todo.forEach(todo => {
todo.addEventListener('dragstart', () => {
todo.classList.add('dragging')
})
})
TLDR
Here is a fiddle, when you create a new todo item it doesnt seem to be picked up by the forEach loop and apply the class
Any help would be much appreciated!
I am making a todo list, i have just about everything for it figured out but one area i am stuck on is my UL and Li.
Basically when you enter items into the list, you have the ability to click the checkbox beside said item when you complete the task, and it will put a line through the text.
But i also want it to move that item to the bottom of the list when it is clicked.
would anyone be able to help me with how i would go about doing that
code Below
// making event listener for adding item
let addBTN = document.getElementById('addBtn');
addBTN.addEventListener('click', addItem);
// this creates a new li based on the entered value in the text box that it gets when you hit the button
// Through Research found that setAttribute isn't really needed and i can just use .id , .type etc
function addItem() {
// Creating needed elements as well as getting text from textbox
let newLi = document.createElement("li");
let myLiValue = document.getElementById('textBoxAdd').value;
let liTextNode = document.createElement("label");
liTextNode.textContent = myLiValue;
// makes div for li
let newDivID = ('div_' + myLiValue);
let newDiv = document.createElement('div');
newDiv.id = newDivID;
// makes checkboxes for the li
let newCheckBoxID = ('checkbox_' + myLiValue);
let newCheckBox = document.createElement('input');
newCheckBox.type = 'checkbox';
newCheckBox.id = newCheckBoxID;
// makes delete button for the li
let newDeleteID = ('deleteButton_' + myLiValue);
let newDeleteButton = document.createElement("button")
newDeleteButton.type = 'button';
newDeleteButton.id = newDeleteID
newDeleteButton.textContent = 'Delete';
//newDeleteButton.setAttribute('onclick', 'deleteItem()');
newDeleteButton.innerHTML = 'Delete';
// appends it to my newDiv
newDiv.appendChild(newCheckBox);
newDiv.appendChild(liTextNode);
newDiv.appendChild(newDeleteButton);
// then appends my new div to the new Li
newLi.appendChild(newDiv);
// this just makes sure a user cant enter in a blank value
if (myLiValue == "") {
alert("Please Enter Something Before Hitting Add Item");
} else {
document.getElementById('theNewList').appendChild(newLi);
document.getElementById('textBoxAdd').value = "";
}
}
//creating event listener for checkbox line through text and moving item
let theList = document.getElementById('theNewList');
theList.addEventListener('click', checkedComplete);
// function that will target every check box in the list and if any get checked then it will add a line through the text
function checkedComplete(event) {
const checkboxElement = event.target;
if (checkboxElement.type === 'checkbox') {
if (checkboxElement.checked) {
checkboxElement.nextElementSibling.style.textDecoration = 'line-through';
// add in moving item
} else {
checkboxElement.nextElementSibling.style.textDecoration = 'none';
}
}
}
// adds deleteItem listener to the list
theList.addEventListener('click', deleteItem);
function deleteItem(event) {
const deleteButton = event.target;
if (deleteButton.type === 'button') {
const deleteParentNode = deleteButton.parentNode;
deleteParentNode.parentNode.removeChild(deleteParentNode);
}
}
You are going to have a storage of you todos, right? Even if you did not think about it, it can do all the work. Just create the array (you could use localStorage to prevent you data from disappearing after browser is restarted) containing your todos and their condition, like
const todos = [{todo:"watch the movie", completed: false}, {...}, {...}]
Now you can easily add or remove items with standard array methods pop&push, delete with splice, filter etc. After array is mdified, just update the page and build your list using Array.map.
You should just add the following logic where you have // add in moving item comment:
const theList = document.getElementById('theNewList');
const lastListItem = theList.children[theList.children.length - 1];
theList.insertBefore(lastListItem, checkboxElement.parentNode.parentNode);
We're selecting your ul and searching for its last li and then we're simply placing the li belonging to the checkboxElement after the last li.
Working example:
// making event listener for adding item
let addBTN = document.getElementById('addBtn');
addBTN.addEventListener('click', addItem);
// this creates a new li based on the entered value in the text box that it gets when you hit the button
// Through Research found that setAttribute isn't really needed and i can just use .id , .type etc
function addItem() {
// Creating needed elements as well as getting text from textbox
let newLi = document.createElement("li");
let myLiValue = document.getElementById('textBoxAdd').value;
let liTextNode = document.createElement("label");
liTextNode.textContent = myLiValue;
// makes div for li
let newDivID = ('div_' + myLiValue);
let newDiv = document.createElement('div');
newDiv.id = newDivID;
// makes checkboxes for the li
let newCheckBoxID = ('checkbox_' + myLiValue);
let newCheckBox = document.createElement('input');
newCheckBox.type = 'checkbox';
newCheckBox.id = newCheckBoxID;
// makes delete button for the li
let newDeleteID = ('deleteButton_' + myLiValue);
let newDeleteButton = document.createElement("button")
newDeleteButton.type = 'button';
newDeleteButton.id = newDeleteID
newDeleteButton.textContent = 'Delete';
//newDeleteButton.setAttribute('onclick', 'deleteItem()');
newDeleteButton.innerHTML = 'Delete';
// appends it to my newDiv
newDiv.appendChild(newCheckBox);
newDiv.appendChild(liTextNode);
newDiv.appendChild(newDeleteButton);
// then appends my new div to the new Li
newLi.appendChild(newDiv);
// this just makes sure a user cant enter in a blank value
if (myLiValue == "") {
alert("Please Enter Something Before Hitting Add Item");
} else {
document.getElementById('theNewList').appendChild(newLi);
document.getElementById('textBoxAdd').value = "";
}
}
//creating event listener for checkbox line through text and moving item
let theList = document.getElementById('theNewList');
theList.addEventListener('click', checkedComplete);
// function that will target every check box in the list and if any get checked then it will add a line through the text
function checkedComplete(event) {
const checkboxElement = event.target;
if (checkboxElement.type === 'checkbox') {
if (checkboxElement.checked) {
checkboxElement.nextElementSibling.style.textDecoration = 'line-through';
const theList = document.getElementById('theNewList');
const lastListItem = theList.children[theList.children.length - 1];
theList.insertBefore(checkboxElement.parentNode.parentNode, lastListItem.nextSilbing);
} else {
checkboxElement.nextElementSibling.style.textDecoration = 'none';
}
}
}
// adds deleteItem listener to the list
theList.addEventListener('click', deleteItem);
function deleteItem(event) {
const deleteButton = event.target;
if (deleteButton.type === 'button') {
const deleteParentNode = deleteButton.parentNode;
deleteParentNode.parentNode.removeChild(deleteParentNode);
}
}
<input id="textBoxAdd" type="text" />
<button id="addBtn" type="button">Add</button>
<ul id="theNewList"></ul>
I am trying to convert this HTML code to be generated by Javascript on the fly for live data.
<div class="dropdown">
<button class="dropbtn">Dropdown</button>
<div class="dropdown-content">
Link 1
Link 2
Link 3
</div>
</div>
Ive found a few methods like: appendChild, getElementById, innerHTML and so on. Here is what I've tried so far. I can't seem to get the data to show up.
stringy = data2.Items[0].groupName.values[i];
var para = document.createElement("div");
var node = document.createTextNode(stringy);
para.appendChild(node);
var element = document.getElementById("parental");
element.appendChild(para);
//create div and give it a class
para.setAttribute('class', 'dropbtn');
var div = document.createElement("div");
div.setAttribute('class', 'dropdown-content');
para.parentNode.insertBefore(div, para.nextSibling);
//create link tags and give them text
var alinky = document.createElement("a");
alinky.setAttribute('id', 'linky');
document.getElementById('linky').innerHTML = "linky poo"
div.appendChild(alinky);
Hopefully someone could fill in the blanks on getting this HTML code to be reproduced with javascript. Thanks in advance!
EDIT:
I am trying to create a dropdown menu like this:
https://www.w3schools.com/howto/tryit.asp?filename=tryhow_css_js_dropdown_hover
However, I am trying to create multiple dropdown menus, that dynamically change in quantity based on a query to DynamoDB (AWS). therefore I am using javascript to create the html tags.
The problem is that the scope of the query function does not allow me to see the data outside of the query function, or even inject data into it.
For example, if I try to get a button description from the query, and write to it descriptionArray[0] = data2.Items[0].description; so that I can append the button to the dropdown div, it doesn't know which iteration I'm on in the for loop due to scope. In this example, descriptionArray[0] will work, but descriptionArray[i] will not work because the for loop is outside the query.
Here is the entire logic:
//group data
var length = data2.Items[0].groupName.values.length;
// create elements
const dpdown1 = document.createElement('div');
// set dpdown1 class
dpdown1.setAttribute('class', 'dropdown');
console.log(dpdown1);
var button = new Array();
var dpdown2 = new Array();
var membersArray = new Array();
var descriptionArray = new Array();
var linksArray = new Array();
var stringy = new Array;
//list groups
for(i = 0; i<length; i++){
// create button, set button attribs
button[i] = document.createElement('button');
button[i].setAttribute('class','dropbtn');
//create dropdown div, set attributes
dpdown2[i] = document.createElement('div');
dpdown2[i].setAttribute('class', 'dropdown-content');
//list of group names
stringy[i] = data2.Items[0].groupName.values[i];
var stringyy = stringy[i];
var desc;
//query group members and description
var docClient1 = new AWS.DynamoDB.DocumentClient({ region: AWS.config.region });
var identityId = AWS.config.credentials.identityId;
var paramsyy = {
ExpressionAttributeValues: {
":v1": stringyy
},
KeyConditionExpression: "groupName = :v1",
TableName: "group"
};
docClient1.query(paramsyy, function(err, data2) {
if (err) {
console.error(err);
}else{
descriptionArray[0] = data2.Items[0].description;
//traverse members
for(k = 0; k<data2.Items[0].members.values.length; k++){
// create dropdown links of members
membersArray[k] = data2.Items[0].members.values[k];
linksArray[k] = document.createElement('a');
linksArray[k].setAttribute('href', '#')
linksArray[k].innerText = membersArray[k];
// nest into dpdown2 div, set dpdown2 attribs
dpdown2[0].appendChild(linksArray[k]);
}
}
});
button[i].innerText = stringyy + ": " + descriptionArray[0];
// nest into dpdown1
dpdown1.appendChild(button[i]);
dpdown1.appendChild(dpdown2[i]);
}
// append to DOM
const target = document.getElementById('target');
target.appendChild(dpdown1);
if I use the I from the first for loop inside the query function, it will give me undefined results.
here's how you can do it with vanilla JavaScipt, there are multiple ways to do it, but this way only uses 4 methods: createElement, setAttribute, appendChild, and getElementById, and directly sets 1 property: innerText.
// create elements
const dpdown1 = document.createElement('div');
const button = document.createElement('button');
const dpdown2 = document.createElement('div');
const link1 = document.createElement('a');
const link2 = document.createElement('a');
const link3 = document.createElement('a');
// set link attribs
link1.setAttribute('href', '#')
link1.innerText = 'Link 1';
link2.setAttribute('href', '#')
link2.innerText = 'Link 2';
link3.setAttribute('href', '#')
link3.innerText = 'Link 3';
// nest into dpdown2, set dpdown2 attribs
dpdown2.appendChild(link1);
dpdown2.appendChild(link2);
dpdown2.appendChild(link3);
dpdown2.setAttribute('class', 'dropdown-content');
// set button attribs
button.setAttribute('class','dropbtn');
button.innerText = "Dropdown"
// nest into dpdown1
dpdown1.appendChild(button);
dpdown1.appendChild(dpdown2);
// set dpdown1 class
dpdown1.setAttribute('class', 'dropdown');
// append to DOM
const target = document.getElementById('target');
target.appendChild(dpdown1);
<div id="target"></div>
You will to append it to something, in this example it's <div id="target"></div> but it could be something else.
Happy coding!
Mainly you are just doing things out of order.
Create the .dropdown <div> with its class.
Complete the .dropbtn <button> with its class and text.
Add the button to the div.
Create the .dropdown-content <div>.
Complete each link with its href attribute and text.
Add each link to the .dropdown-content <div>.
Add the .dropdown-content div to the .dropdown <div>.
Find the parent element in the document.
Append the whole complete .dropdown <div> to the document.
var para = document.createElement("div"); //make .dropdown div
para.setAttribute('class', 'dropdown'); //add .dropdown class to div
var button = document.createElement("button"); //create button
button.setAttribute('class', 'dropbtn'); //add .dropbtn class to button
var node = document.createTextNode('Dropdown'); //create button text
button.appendChild(node); //add text to button
para.appendChild(button); //add button to .dropdown div
var div = document.createElement("div"); //create .dropdown-content div
div.setAttribute('class', 'dropdown-content'); //add .dropdown-content class to div
//repeat for all necessary links
var alinky = document.createElement("a"); //creat link
alinky.setAttribute('href', '#'); //set link href attribute
var alinkyText = document.createTextNode("Link 1"); //create text for link
alinky.appendChild(alinkyText); //add text to link
div.appendChild(alinky); //add link to dropdown div
para.appendChild(div); //add .dropdown-content div to .dropdown div
var element = document.getElementById("parental"); //find parent element
element.parentNode.insertBefore(para, element.nextSibling); //add .dropdown div to the bottom of the parent element
<div id="parental">
</div>
I have a to-do list application on my website that I built using JavaScript. It works perfectly in Google Chrome, but it doesn't work in Mozilla Firefox. I have read that each browser interprets JavaScript differently, but I haven't been able to pinpoint exactly what the problem is in the code.
So, what happens in Firefox is this: When you type something into the text input and click the "Add Task" button, it does show that a task has been added. However, the label appears blank, as do the Edit and Delete buttons. All of the functionality appears to work as normal (the Edit and Delete buttons work properly, they just don't display the text).
In the code, the each list item is created by a function called createTask. Its code is:
var createTask = function(taskString) {
// taskString is the value of the text input (whatever the user wants the task to read)
// Create Elements
var listItem = document.createElement("li");
var checkbox = document.createElement("input");
var label = document.createElement("label");
var editInput = document.createElement("input");
var editButton = document.createElement("button");
var deleteButton = document.createElement("button");
// Modify Elements
checkbox.type = "checkbox";
label.innerText = taskString;
editInput.type = "text";
editButton.innerText = "Edit";
deleteButton.innerText = "Delete";
// Add Event Listeners
checkbox.addEventListener("change", markTask);
editButton.addEventListener("click", editTask);
deleteButton.addEventListener("click", deleteTask);
// Append the Elements to the List Item
listItem.appendChild(checkbox);
listItem.appendChild(label);
listItem.appendChild(editInput);
listItem.appendChild(deleteButton);
listItem.appendChild(editButton);
return listItem;
}
Then, the function addTask appends listItem to the unordered list that is the tasks list.
var addTask = function() {
if (addInput.value === "") {
addError.style.display = "block"; // Display error message if no input
} else {
addError.style.display = "none"; // Stop displaying error message
var listItem = createTask(addInput.value); // Put user input into createTask function
tasksList.appendChild(listItem); // Add the new list item to the unordered list
addInput.value = ""; // Reset the text input field to blank
addInput.focus();
}
}
Looking more closely, within the createTask function, there is:
label.innerText = taskString;
editButton.innerText = "Edit";
deleteButton.innerText = "Delete";
So, I thought that the innerText property may not work properly in Firefox, but I tried changing it to innerHTML and textContent, and that doesn't work either!
Any ideas?
innerText is deprecated.
Try using textContent instead.
This issue has been described here:
'innerText' works in IE, but not in Firefox
use .textContent and log listItem in console you will see they are constructed properly.below is your code with small changes.tested in firefox:
var createTask = function(taskString) {
// taskString is the value of the text input (whatever the user wants the task to read)
// Create Elements
var listItem = document.createElement("li");
var checkbox = document.createElement("input");
var label = document.createElement("label");
var editInput = document.createElement("input");
var editButton = document.createElement("button");
var deleteButton = document.createElement("button");
// Modify Elements
checkbox.type = "checkbox";
label.textContent = taskString;
editInput.type = "text";
editButton.textContent = "Edit";
deleteButton.textContent = "Delete";
//alert(deleteButton.textContent);
// Add Event Listeners
// checkbox.addEventListener("change", markTask); // commented these because i do not had these objects.
// editButton.addEventListener("click", editTask);
// deleteButton.addEventListener("click", deleteTask);
// Append the Elements to the List Item
listItem.appendChild(checkbox);
listItem.appendChild(label);
listItem.appendChild(editInput);
listItem.appendChild(deleteButton);
listItem.appendChild(editButton);
console.log(listItem);
return listItem;
}