I received answers regarding the following contents.
Create Todo list with Javascript
If you enter too many characters, the "state" part will be misaligned. Like in the video, I want to expand the width of the "comment" according to the input value. What should I do?
See also the image.
Have already updated my answer to acomodate this additional bit on the same question :). See this and read the comments on the snippets:
https://stackoverflow.com/a/62356950/4650975
document.addEventListener('DOMContentLoaded', function() {
// 必要なDOM要素を取得。
const addTaskTrigger = document.getElementsByClassName('addTask-trigger')[0];
const addTaskTarget = document.getElementsByClassName('addTask-target')[0];
const addTaskValue = document.getElementsByClassName('addTask-value')[0];
//ID用のインデックスを定義
let nextId = 0;
const addTask = (task,id) => {
// 表のタグを生成する
const tableItem=document.createElement('thead');
const addButton = document.createElement('button');
const removeButton = document.createElement('button');
addButton.style.margin = "5px"; //<------- Added a style here
removeButton.style.margin ="5px"; //<------- Added a style here
// それぞれ作業中、削除という言葉をボタンに入れる
addButton.innerText = '作業中';
removeButton.innerText = '削除';
//ボタンを押したら以下の作業をする
removeButton.addEventListener('click', () => removeTask(removeButton));
// IDを表示するspan要素を作成して tableItem に追加
const idSpan = document.createElement('span');
idSpan.innerText = id;
idSpan.style.marginRight = "20px"; //<------- Added a style here
tableItem.append(idSpan);
const taskSpan = document.createElement('span');
taskSpan.style.width = "60px"; //<------- Added a style here
taskSpan.style.display = "inline-block"; //<------- Added a style here
taskSpan.style.overflow = "hidden"; // <----- This styling for trimming the text if it exceeds certain width
taskSpan.style.textOverflow = "ellipsis"; // <------- This will append a (...) to the exceeding text
taskSpan.innerText = task;
taskSpan.title = task; //If you hover on the text full text will be displayed. In production code, you might like to use fancy tooltips, say, from bootstrap, for this
tableItem.append(taskSpan); //<------- changed this
//入力タスクを表示
addTaskTarget.appendChild(tableItem);
// 作業中ボタンを追加
tableItem.appendChild(addButton);
// 削除ボタンを追加
tableItem.appendChild(removeButton);
};
// 追加ボタンに対して、タスク登録イベントを設定
addTaskTrigger.addEventListener('click', event => {
const task = addTaskValue.value;
addTask(task,nextId ++);
addTaskValue.value = '';
});
});
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel ="stylesheet" href="css/style.css">
<title>Todoリスト</title>
</head>
<body>
<h1>Todoリスト</h1>
<p>
<input type="radio" name="status" value="1" checked="checked">全て
<input type="radio" name="status" value="2">作業中
<input type="radio" name="status" value="3">完了
</p>
<p></p>
<table>
<thead>
<tr>ID コメント 状態</tr>
</thead>
<tbody class ="addTask-target">
<tr>
</tr>
</tbody>
</table>
<h2>新規タスクの追加</h2>
<input class="addTask-value" type="text" />
<button class="addTask-trigger" type="button">追加</button>
<script src="js/main.js"></script>
</body>
</html>
Related
I have a todo html element whose inner html i want to save in localstorage through use of html but i am unable to figure out how i would do it.
My javascript code
// Load everything
// get DOM Elements
let to_do_input = document.getElementById("todo-input");
let addBtn = document.getElementById("addBtn");
let display = document.getElementsByClassName("display")[0];
// Event Listeners
addBtn.addEventListener("click", () => {
// Add DOM ELements
let list = document.createElement("ul");
let todos = document.createElement("li");
let deleteBtn = document.createElement("button");
deleteBtn.innerText = "Delete";
// let saveBtn = document.createElement("button");
// saveBtn.innerText = "Save";
display.appendChild(list);
list.appendChild(todos);
list.appendChild(deleteBtn);
// list.append(saveBtn);
// Class names
list.classList.add("list");
todos.classList.add("todos");
deleteBtn.classList.add("deleteBtn");
// saveBtn.classList.add("saveBtn");
// Set values
todos.innerHTML = to_do_input.value;
to_do_input.value = null;
// delete todo
deleteBtn.addEventListener("click", () => {
list.innerHTML = null;
});
// SAVE todo
// saveBtn.addEventListener("click", () => {
// // let arr = [];
// let savedTodo = arr.push(todos.innerHTML);
// localStorage.setItem("todo", JSON.stringify(savedTodo));
// });
// Set saved todo
});
and my html
<!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" />
<meta name="description" content="This web app provides you with accessibility of todo list" />
<title>Simple To-Do-List</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<h2>A Reliable To-Do-App</h2>
<div class="text-input center">
<input type="text" id="todo-input" placeholder="Write you task here.." />
<button type="button" id="addBtn" )>Add</button>
</div>
<div class="display"></div>
</div>
<script src="app.js"></script>
</body>
</html>
I have reviewed from other sites on how to do it but when i tried the array method , it returned numbers or when i tried to push todos into empty array , it didnt do anything. Also i dont know how i will convert the html element into an object to use it while making todo. Rest all the things work fine.
You need to set a array to save list,
So just edit your JS code to :
// Load everything
// get DOM Elements
let to_do_input = document.getElementById('todo-input')
let addBtn = document.getElementById('addBtn')
let display = document.getElementsByClassName('display')[0]
let todoArray = []
// Event Listeners
addBtn.addEventListener('click', () => {
// Add DOM ELements
let list = document.createElement('ul')
let todos = document.createElement('li')
let deleteBtn = document.createElement('button')
deleteBtn.innerText = 'Delete'
// let saveBtn = document.createElement("button");
// saveBtn.innerText = "Save";
display.appendChild(list)
list.appendChild(todos)
list.appendChild(deleteBtn)
// list.append(saveBtn);
// Class names
list.classList.add('list')
todos.classList.add('todos')
deleteBtn.classList.add('deleteBtn')
// saveBtn.classList.add("saveBtn");
// Set values
todos.innerHTML = to_do_input.value
todoArray.push(to_do_input.value)
to_do_input.value = null
// delete todo
deleteBtn.addEventListener('click', () => {
list.innerHTML = null
})
// SAVE todo
// saveBtn.addEventListener("click", () => {
// // let arr = [];
// let savedTodo = arr.push(todos.innerHTML);
// localStorage.setItem("todo", JSON.stringify(savedTodo));
// });
// Set saved todo
localStorage.setItem('todo', JSON.stringify(todoArray))
})
Super new to all of this so this might be some beginner troubleshooting. The list seems to be working where I'm adding a list element to the UL with a checkbox and delete button. When checkbox is checked it puts a line through the text and when the delete button is clicked it deletes the list element. The assignment asks to save to localStorage so that when refreshed, the list items still remain, and I'm getting super confused by this. What I have now seems to be saving my list elements to an array but I don't understand how to get them to save and stay on the page.
const form = document.querySelector('form');
const input = document.querySelector('#todoInput');
const newElement = document.querySelector('ul');
const savedToDos = JSON.parse(localStorage.getItem('todos')) || [];
newElement.addEventListener('click', function(e) {
if(e.target.tagName === 'BUTTON') {
e.target.parentElement.remove()
}
})
function addToList(text) {
const li = document.createElement('li');
const checkbox = document.createElement('input');
const button = document.createElement('button');
button.innerText = "Delete";
checkbox.type = 'checkbox';
checkbox.addEventListener('change', function() {
li.style.textDecoration = checkbox.checked ? 'line-through' : 'none';
})
li.innerText = text;
li.insertBefore(checkbox, li.firstChild);
li.appendChild(button);
return li;
};
form.addEventListener('submit', function(e) {
e.preventDefault();
const newListItem = addToList(input.value);
input.value = '';
newElement.append(newListItem);
savedToDos.push(newListItem.innerText);
localStorage.setItem('todos', JSON.stringify(savedToDos));
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ToDo App</title>
<link rel="stylesheet" href="app.css">
</head>
<body>
<div>
<h1>Todo List</h1>
<form action="">
<input type="text" id="todoInput" placeholder="Add To Todo List">
<button class="add-button">Add</button>
</form>
<ul id="todoList">
</ul>
</div>
<script src="app.js"></script>
</body>
</html>
It looks like you're failing to populate the DOM when the page loads.
After you retrieve the items from local storage (which you're already doing), loop through the list and add each of them to the DOM:
// After this line, which you've already written:
const savedToDos = JSON.parse(localStorage.getItem('todos')) || [];
// Loop through savedToDos, and for each one, insert a new list:
savedToDos.forEach(function(value) {
const newListItem = addToList(value);
newElement.append(newListItem);
});
Every browser has local storage where we can store data and cookies. just go to the developer tools by pressing F12, then go to the Application tab. In the Storage section expand Local Storage.
this piece of code might help you
// Store Task
function storeTaskInLocalStorage(task) {
let tasks;
if(localStorage.getItem('tasks') === null){
tasks = [];
} else {
tasks = JSON.parse(localStorage.getItem('tasks'));
}
tasks.push(task);
localStorage.setItem('tasks', JSON.stringify(tasks));
}
I am creating a simple to do list using jQuery and local storage. I am also trying to add a button for each li I add to clear the item from the list. My list does not stick upon refresh and I can't figure out how to load the button, does the button need to happen on the HTML side?
The adding to the list functions work great its just the storage to local storage that I seem to be missing something.
I created a jsfiddle for this code and the local storage seems to work fine but it will not work on my xampp. Also I can get the done button to appear but it won't removeItem.
https://jsfiddle.net/blen6035/287pc153/7/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Task List</title>
<link rel="stylesheet" href="main.css">
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="tasks.js"></script>
</head>
<body>
<aside>
<h2>Add a task</h2>
<label for="task">Task:</label>
<input type="text" id="task" name="task"><br>
<label> </label>
<input type="button" id="add" name="add" value="Add Task">
</aside>
<main>
<h1>Task list</h1>
<ul id="listOfTasks"></ul>
</main>
<footer></footer>
</body>
</html>
"use strict"
$(document).ready(function() {
let listOfTasks = JSON.parse( localStorage.getItem("tasks"));
if( listOfTasks == undefined ){
listOfTasks = [];
}
for( let i = 0; i < listOfTasks.length; i++){
let li = $('<li> Done
</li>').text(listOfTasks[i]);
$('#listOfTasks').append(li);
}
$('#add').click(function(){
let task = $('#task').val();
listOfTasks.push(task);
localStorage.setItem("tasks", JSON.stringify(listOfTasks)
);
let li = $('<li></li>').text(task);
$('#listOfTasks').append('<li>'+ task +'<input type="submit"
class="done" value= "Done">' + '</li>');
$('#task').val(' ').focus();
});
$('.done').on('click', '.delete',function(){
$(this).parent().remove();
});
/*$('#done').click(function(){
localStorage.removeItem;
$('#listOfTasks').html('');
});*/
}); // end ready
Is this what you are trying to do ?
Note that I had to polyfill local storage to make this work in a snippet, replace fakeLocalStorage by localStorage
const listOfTasksElement = $('#listOfTasks')
const taskInputElement = $('#task')
const listOfTasks = JSON.parse(fakeLocalStorage.getItem('tasks')) || []
const updateTasks = () => fakeLocalStorage.setItem('tasks', JSON.stringify(listOfTasks))
const addTask = task => {
const taskElement = $('<li></li>').text(task)
const doneElement = $('<span>Done</span>').click(() => {
const index = listOfTasksElement.find('li').index(taskElement)
taskElement.remove()
listOfTasks.splice(index, 1)
updateTasks()
})
taskElement.append(doneElement)
listOfTasksElement.append(taskElement)
listOfTasks.push(task)
updateTasks()
}
listOfTasks.forEach(addTask)
$('#add').click(() => {
addTask(taskInputElement.val())
taskInputElement.val('').focus()
})
<ul id="listOfTasks"></ul>
<input id="task"><button id="add">Add</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
// local storage doesn't work in stack overflow snippets,
// this is just a poor in-memory implementation
const fakeLocalStorage = {
_data: {},
setItem(k, v) { return this._data[k] = v },
getItem(k) { return this._data.hasOwnProperty(k) ? this._data[k] : null }
}
</script>
I'm creating a filtered table in JavaScript. Everything is okay. However, the only line that doesn't seem to work is inputValue = ''. Not sure why it doesn't want to clear the field after filtering is done.
If you replace that with document.querySelector('.form__input').value things seem to work, but I don't want to repeat the same code. I already declared it above as inputValue.
const initValues = [
'Walmart',
'State Grid',
'Sinopec Group',
'China National Petrolium',
'Royal Dutch Shell',
'Toyota Motor',
'Volkswagen',
'BP',
'Exxon Mobil',
'Berkshire Hathaway'
];
const tableCreation = array => {
const tableBody = document.querySelector('.table__body');
document.querySelectorAll('tr').forEach(el => el.parentNode.removeChild(el));
array.forEach(el => {
const row = document.createElement('tr');
const cell = document.createElement('td');
const cellText = document.createTextNode(el);
cell.appendChild(cellText);
row.appendChild(cell);
tableBody.appendChild(row);
});
};
tableCreation(initValues);
const filterTable = event => {
event.preventDefault();
let inputValue = document.querySelector('.form__input').value;
const filtered = initValues.filter(el => el.toLowerCase().includes(inputValue.toLowerCase()));
if (filtered) {
inputValue ? tableCreation(filtered) : tableCreation(initValues);
}
inputValue = '';
};
document.querySelector('.form__button').addEventListener('click', filterTable);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="./css/3.css">
<title>Filtered list</title>
</head>
<body>
<form class="form" id="form">
<label for="filter">Filtered: </label>
<input class="form__input" type="text" id="filter" name="input" placeholder="Insert phrase...">
<button class="form__button" form="form" type="submit">Filter</button>
</form>
<table class="table">
<tbody class="table__body"></tbody>
</table>
<script src="./js/3.js"></script>
</body>
</html>
The variable inputValue is holding only the actual value of the field, it's detached from it.
You can save a reference to the field as a variable and clean the value as follows:
const inp = document.querySelector('.form__input');
inp.value = '';
let inputValue = document.querySelector('.form__input').value;
this line return the string value of the input.
When you are trying inputValue = ''; you are only changing the value of the variable 'inputValue' but not of the input field.
to do this juste save you field as a variable instead of it's value and then change it's value :
let inputField = document.querySelector('.form__input');
const filtered = initValues.filter(el => el.toLowerCase().includes(inputValue.toLowerCase()));
if (filtered) {
inputValue ? tableCreation(filtered) : tableCreation(initValues);
}
inputField.value = '';
You already get value only from inputvalue., but u can't change that value so
get dom instance also
kindly change this code to
const filterTable = event => {
event.preventDefault();
let inputElement = document.querySelector('.form__input'),
inputValue = inputElement.value;
const filtered = initValues.filter(el => el.toLowerCase().includes(inputValue.toLowerCase()));
if (filtered) {
inputValue ? tableCreation(filtered) : tableCreation(initValues);
}
inputElement.value = '';
};
I'm having trouble retrieving the textContent of some of my elements. The issue arises from line 88-91. Line 91 retrieves a value of null. I don't understand why this is so. I was able to verify this by setting line 91 to a variable and console.log() to the console and the value was returned as null. Additionally, at line 99 my console is giving me an error of, "Uncaught TypeError: Cannot read property 'firstChild' of undefined". I'm assuming this error is related to the issue I'm having at lines 88-91, but I'm not entirely sure because it says undefined and not null. The HTML elements have text inside of them so I don't know why it would be returning null. I'm not sure what I'm missing. Any insight is greatly appreciated. Thanks in advance for you guys insight!
HTML Markup:
(function(){
const taskList = document.querySelector('ul');
const completedList = document.querySelector('#completed-task');
const editTask = document.querySelector('#edit-task');
const cover = document.querySelector('.cover');
const editedInfo = document.querySelector('#edited-info');
const editedDate = document.querySelector('#edited-date');
const editedName = document.querySelector('edited-item');
let editedListItem;
document.querySelector('button').addEventListener('click', function(e) {
/* Preventing Page Default Page Refresh*/
e.preventDefault();
/* Grabbing User Input */
let userInput = document.querySelector('input').value;
let userDate = document.getElementById('date').value;
let userInfo = document.getElementById('userInfo').value;
/* Creating Elements */
let listItem = document.createElement('li');
let container = document.createElement('div');
let item = document.createElement('span');
let deletebutton = document.createElement('span');
/* Update: February 4, 2019 --> Creating Info Box */
let infoBox = document.createElement('div');
let dueDate = document.createElement('p');
let info = document.createElement('p');
let span = document.createElement('span');
/* Update: February 5, 2019 --> Creating Edit button */
let edit = document.createElement('span');
/* Adding Attributes */
container.setAttribute('class', 'container');
deletebutton.setAttribute('class','delete');
infoBox.setAttribute('class','info');
edit.setAttribute('class', 'edit');
/* Setting User Input */
item.textContent = userInput;
span.textContent = userDate;
info.textContent = userInfo;
deletebutton.textContent = "Discard";
dueDate.textContent = "Due: ";
edit.textContent = "Edit";
/* Adding Elements to List */
taskList.appendChild(listItem);
listItem.appendChild(container);
container.appendChild(item);
container.appendChild(deletebutton);
listItem.appendChild(infoBox);
infoBox.appendChild(dueDate);
infoBox.appendChild(info);
dueDate.appendChild(span);
infoBox.appendChild(edit);
});
document.querySelector('#task-list').addEventListener('click',function(event){
if(event.target.className == 'delete') {
const li = event.target.parentElement;
li.parentElement.removeChild(li);
}
});
/* Update: February 4, 2019 --> Hide Tasks Checkbox */
document.forms['hide-task'].addEventListener('change', function(event){
const checkbox = document.querySelector('input[type="checkbox"]');
if (checkbox.checked === true) {
taskList.style.display = 'none';
} else {
taskList.style.display = 'block';
}
});
taskList.addEventListener('click', function(event){
if (event.target.className == 'complete') {
let parent = event.target.parentElement.parentElement;
completedList.appendChild(parent);
}
/******* ISSUE OCCURS IN THIS CODE BLOCK *************/
if (event.target.className == 'edit') {
event.preventDefault();
editTask.style.display = 'flex';
cover.style.display = 'block';
editedDate.value = event.target.previousSibling.previousSibling.textContent;
editedInfo.value = event.target.previousSibling.textContent;
editedName.value = event.target.parentElement.previousSibling.firstChild.textContent;
editedListItem = event.target.parentElement.parentElement;
}
});
document.querySelector('#change').addEventListener('click', function(event){
editedListItem.firstChild.firstChild.textContent = editedName.value;
editedListItem.lastChild.firstChild.textContent = editedDate.value;
editedListItem.lastChild.lastChild.textContent = editedInfo.value;
editTask.style.display = 'none';
cover.style.display = 'none';
});
})()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>To Do List</title>
</head>
<body>
<div class="cover"></div>
<h1>To do List</h1>
<form>
<div id="input-button">
<input type="text" placeholder="Add an item..." class="item">
<button type="submit" class="add">+</button>
</div>
<div>
<input type="text" placeholder="Due Date..." id="date">
<input type="text" placeholder="About the task..." id="userInfo">
</div>
</form>
<hr>
<ul id="task-list">
<li>
<div class="container">
<span class="title">Example Task</span>
<span class="delete">Discard</span>
</div>
<!-- Update: Feb #, 2019 -->
<div class="info">
<p>Due: <span>January 15, 2019</span></p>
<p>This is some example text that adds additional context or information for the task</p>
<span class="edit">Edit</span>
</div>
</li>
</ul>
<!-- Update: February 5, 2019 -->
<ul id="completed-task">
<li id="title">Completed Tasks</li>
</ul>
<!-- Update: February 4, 2019 -->
<form id="hide-task">
<div>
<input type="checkbox" name="hide-task">
<label for="hide-task">Hide Tasks</label>
</div>
</form>
<form id="edit-task">
<input type="text" placeholder="Edit item..." id="edited-item">
<input type="text" placeholder="Edit Due Date..." id="edited-date">
<input type="text" placeholder="Edit about the task..." id="edited-info">
<button id="change" type="button">Change</button>
</form>
</body>
</html>
After a break and some dinner, I started debugging with a fresh set of eyes and an unfrustrated mind and found the bugs. Everything is now working properly.
1st Issue:
A Typo in the querySelector was responsible for one of the variables to return
textContent error.
Solution:
const editedName = document.querySelector('#edited-item');
2nd Issue:
For the most part previousSibling and previousElementSibling return the element, but
previousSibling will return any kind of sibling. Some browsers add white space around
the elements and so previousSibling will grab the white space around the element
instead, but previousElementSibling always grabs the Element. My initial code was
grabbing the white space around the element.
Solution:
taskList.addEventListener('click', function(event){
if (event.target.className == 'complete') {
let parent = event.target.parentElement.parentElement;
completedList.appendChild(parent);
}
if (event.target.className == 'edit') {
event.preventDefault();
editTask.style.display = 'flex';
cover.style.display = 'block';
editedDate.value = event.target.previousElementSibling.previousElementSibling.firstElementChild.textContent;
editedInfo.value = event.target.previousElementSibling.textContent;
editedName.value = event.target.parentElement.previousElementSibling.firstElementChild.textContent;
editedListItem = event.target.parentElement.parentElement;
}
});
document.querySelector('#change').addEventListener('click', function(event){
editedListItem.firstElementChild.firstElementChild.textContent = editedName.value;
editedListItem.lastElementChild.firstElementChild.firstElementChild.textContent = editedDate.value;
editedListItem.lastElementChild.firstElementChild.nextElementSibling.textContent = editedInfo.value;
editTask.style.display = 'none';
cover.style.display = 'none';
});