I called the function inside the backticks onclick of the input and lis and on fontawesome icon it is not calling the function but the onclick is working as it shows in console.
and here is the code.
let editId;
let isEditTask = false;
let todos = JSON.parse(localStorage.getItem('todo-list'));
function showTodo(filter) {
let liTag = '';
if (todos) {
todos.forEach((todo, id) => {
const completed = todo.status === 'completed' ? 'checked' : '';
if (filter === todo.status || filter === 'all') {
liTag += `<li class="task">
<label for="${id}">
<input onclick="updateStatus(this)" type="checkbox" id="${id}" ${completed}>
<p class="${completed}">${todo.name}</p>
</label>
<div class="settings">
<i onclick="showMenu(this)" class="uil uil-ellipsis-v"></i>
<ul class="task-menu">
<li onclick='editTask(${id}, "${todo.name}")'><i class="uil uil-pen"></i>Edit</li>
<li onclick='deleteTask(${id}, "${filter}")'><i class="uil uil-trash"></i>Delete</li>
</ul>
</div>
</li>`;
}
});
}
taskBox.innerHTML = liTag || '<span>You don\'t have any task here</span>';
const checkTask = taskBox.querySelectorAll('.task');
!checkTask.length ? clearAll.classList.remove('active') : clearAll.classList.add('active');
taskBox.offsetHeight >= 300 ? taskBox.classList.add('overflow') : taskBox.classList.remove('overflow');
}
showTodo('all');
filters.forEach((btn) => {
btn.addEventListener('click', () => {
document.querySelector('span.active').classList.remove('active');
btn.classList.add('active');
showTodo(btn.id);
});
});
function updateStatus(selectedTask) {
const taskName = selectedTask.parentElement.lastElementChild;
if (selectedTask.checked) {
taskName.classList.add('checked');
todos[selectedTask.id].status = 'completed';
} else {
taskName.classList.remove('checked');
// todos[selectedTask.id].status = "pending";
}
localStorage.setItem('todo-list', JSON.stringify(todos));
}
I tried to not use backticks and create each of them using createElement.
I am still working on that way
You could use event delegation here, sample example below, we target ul and then the click on particular li element and do whatever intended to do
Event delegation tutorial ...
const sample = document.querySelector("#sample");
const ul = document.createElement("ul");
sample.append(ul)
const fruits = ["apple","orange","grapes"];
let li = "";
fruits.forEach((fruit)=>{
li += `<li id=${fruit}>${fruit}</li>`;
ul.innerHTML= li;
})
ul.addEventListener("click",function(e){
if(e.target?.tagName === "LI"){
console.log(e.target.innerText)
}
})
<div id="sample"></div>
Related
HTML:
The unordered list has an id of add-books
<div id="book-list">
<h2 class="title">Books to Read</h2>
<ul>
<li>
<span class="name">Atomic Habit</span>
<span class="delete">delete</span>
</li>
<li>
<span class="name">Rich Dad, Poor Dad</span>
<span class="delete">delete</span>
</li>
<li>
<span class="name">Richest Man in Babylon</span>
<span class="delete">delete</span>
</li>
<li>
<span class="name">How to Handle people</span>
<span class="delete">delete</span>
</li>
<li>
<span class="name">Hearing from God</span>
<span class="delete">delete</span>
</li>
</ul>
</div>
<form action="" id="add-book">
<input type="checkbox" id="hide">
<label for="hide">Hide all books</label>
<input type="text" placeholder="Add a book..">
<button>Add</button>
</form>
javascript:
I find it difficult to prevent the page from reloading to its default state when a user has uploaded or updated the reading list. For some reason, the code isn't working.
What do I add to my HTML and JS file in order to save values to local storage, read them as well as load them from local storage so that they fill into the list automatically.
document.addEventListener('DOMContentLoaded', function(){
const list = document.querySelector('#book-list ul');
//delete books
list.addEventListener('click', function(e){
if (e.target.className == 'delete') {
const li = e.target.parentElement;
list.removeChild(li);
}
});
//add books
const addForm = document.forms['add-book'];
addForm.addEventListener('submit', function(e){
e.preventDefault();
const value = addForm.querySelector('input[type="text"]').value;
//create element
const li = document.createElement("li");
const bookName = document.createElement('span');
const deleteBtn = document.createElement('span');
//add content
deleteBtn.textContent = 'delete'
bookName.textContent = value;
//add classes
bookName.classList.add('name');
deleteBtn.classList.add('delete');
//append to DOM
li.appendChild(bookName);
li.appendChild(deleteBtn);
list.appendChild(li);
});
/*
let arrayList = Array.from(list);
window.onload = () => {
if (JSON.parse(localStorage.getItem("mylist")) != null) {
arrayList = JSON.parse(localStorage.getItem("mylist"));
}
console.log(arrayList);
};
/*
localStorage.setItem("listkey", JSON.stringify(list));
var storedArray = localStorage.getItem("listkey");
list = JSON.parse(storedArray);*/
/*
if (localStorage.getItem("mylist") == null ) {
localStorage.setItem("mylist", "[]");
}
var old = JSON.parse(localStorage.getItem("mylist"));
old.push(list.appendChild(li)
);
localStorage.setItem("mylist", JSON.stringify (old));
function view() {
if (localStorage.getItem("data")) != null {
list.querySelectorAll('li') = JSON.parse(localStorage.getItem("mylist"))
}
}
/*
let m = [...list].map(function(lis){
return {
name: lis.bookName,
delete: lis.deleteBtn
}
});
localStorage.setItem('listkey', JSON.stringify(m));
window.addEventListener('load', () => {
const myList = JSON.parse(localStorage.getItem('listkey'));
});
let data = JSON.parse(localStorage.getItem('mylist')) || [];
data.push([
value,
'delete'
]);
localStorage.setItem('mylist', JSON.stringify(data));
window.addEventListener('load', function()
{
const data = JSON.parse(localStorage.getItem('mylist'));
});
*/
/*
let data = JSON.parse(localStorage.getItem('todo')) || [];
data.push([
task,
btn_selected_color
]);
localStorage.setItem('todo', JSON.stringify(data));
}*/
** I want when to click on the active button if the checkbox is checked to add filtered class in HTML element but it doesn't work and give me an undefined error in this line check.parentElement.classList.add("filtered"); **
<ul class="ul-list"></ul>
</section>
</main>
<footer class="footer">
<button class="all footer-btn">All</button>
<button class="active footer-btn">Active</button>
<button class="complete footer-btn">Complete</button>
</footer>
let check = document.querySelectorAll(".complete-txt");
let complete_btn = document.querySelector(".complete");
let active_btn = document.querySelector(".active");
let all_btn = document.querySelector(".all");
let edit_list = document.querySelector(".edit-list");
let main_text = document.querySelector(".main-text");
let list_item = document.querySelector(".list-item");
let footer = document.querySelector(".footer");
const generateTemplate = (todo) => {
const html = `
<li class="list-item">
<input type="checkbox" class="complete-txt" name="" id="check"><span class="main-text">${todo}</span><div class="edit-list"></div><div class="delete-list"></div>
</li>
`;
list.innerHTML += html;
};
// add todos event
addForm.addEventListener("submit", (e) => {
e.preventDefault();
const todo = addForm.add.value.trim();
if (todo.length) {
generateTemplate(todo);
addForm.reset();
}
});
active_btn.addEventListener("click", function () {
let check_id = document.querySelector(".complete-txt");
// check.forEach(function () {
debugger;
if (check.checked !== "true") {
check.parentElement.classList.add("filtered");
console.log("hi");
}
// });
// console.log("hi");
console.log("hi");
// console.log(check.checked.value);
});
if the larger document fixes all other inconcistencies you should be able to change the eventlistener to
active_btn.addEventListener("click", function () {
let check_id = document.querySelector(".complete-txt");
if (check_id.checked !== "true") {
check_id.parentElement.classList.add("filtered");
}
});
BUT!!! this will not "fix" all of your errors, like defining let check before the checkbox is created with generateTemplate
i'm a beginner trying to learn JS, I have made this todo app, everything's working fine but for some reason the filter function won't work, i tried everything I could think of. Please help.
I had already made this app with materialize and it worked fine.
I already tried to use task.style.display and task.className but it didn't work.
SITE DEMO
https://codepen.io/salma-py97/pen/mdOdLvo?editors=1010
here's the HTML:
<body class="bg-secondary">
<div class="container">
<div class="row">
<div class="col">
<div class="col-md-6 mx-auto">
<div class="card card-body text-center mt-5">
<h2 class="display-5 pb-3">
<i class="fas fa-list"></i> Task List
</h2>
<form id="task-form">
<div class="form-group">
<input type="text" class="form-control" id="task-input" placeholder="Task" value="">
</div>
<div class="form-group">
<input type="submit" value="Add Task" class="btn btn-dark btn-block">
</div>
</form>
<hr>
<h3 class="display-5">Task</h3>
<div class="form-group">
<input type="text" class="form-control" id="filter-tasks" placeholder="Filter Tasks">
</div>
<ul class="list-group mb-4" id="task-list"></ul>
<div class="form-group">
<input type="submit" class="btn btn-large btn-dark mx-auto" id="clear-tasks" value="Clear Tasks">
</div>
</div>
</div>
</div>
</div>
</div>
here's the JS:
// Define UI Variables
const form = document.querySelector('#task-form');
const taskInput = document.querySelector('#task-input');
const filter = document.querySelector('#filter-tasks')
const taskList = document.querySelector("#task-list");
const clearBtn= document.querySelector("#clear-tasks");
// Load All Event Listeners
loadEventListeners();
// Event Listeners
function loadEventListeners(){
// DOM Event Load
document.addEventListener('DOMContentLoaded', getTasks);
// Add Task
form.addEventListener('submit', addTask);
// Remove task (Event delegation --> putting the eventlistener on the parent element(ul))
taskList.addEventListener('click', removeTask);
// filter Tasks
filter.addEventListener('keyup', filterTasks);
// Clear Tasks
clearBtn.addEventListener('click', clearTasks)
}
// Event Handlers
// Get ALL the Tasks when the DOM Loads
function getTasks(){
let tasks;
if (localStorage.getTasks("tasks")===null){
tasks=[];
} else {
tasks=JSON.parse(localStorage.getItem("tasks"));
}
tasks.forEach(function(task){
// Create li element
const li = document.createElement('li');
// Add Bootstrap4 class
li.className = 'list-group-item d-flex justify-content-between'
// Create TextNode and append to li
li.appendChild(document.createTextNode(task));
// Create link element
const link = document.createElement('a');
// Add class to link
link.className='delete-item';
// Add icon innerHTML
link.innerHTML = '<i class= "fa fa-remove"></i>';
// append link to li
li.appendChild(link);
// append li to ul
taskList.appendChild(li);
})
}
//Add Task
function addTask(e){
if(taskInput.value === ""){
alert("Add task");
} else {
// Create li element
const li = document.createElement('li');
// Add Bootstrap4 class
li.className = 'list-group-item d-flex justify-content-between'
// Create TextNode and append to li
li.appendChild(document.createTextNode(taskInput.value));
// Create link element
const link = document.createElement('a');
// Add class to link
link.className='delete-item';
// Add icon innerHTML
link.innerHTML = '<i class= "fa fa-remove"></i>';
// append link to li
li.appendChild(link);
// append li to ul
taskList.appendChild(li);
// store in LocalStorage
AddTasktoLocalStorage(taskInput.value);
// clear taskInput
taskInput.value='';
// Prevent Default behaviour of forms
e.preventDefault();
}
}
// Add task to LocalStorage
function AddTasktoLocalStorage(task){
let tasks;
if (localStorage.getItem("tasks")=== null){
tasks=[];
} else {
tasks= JSON.parse(localStorage.getItem("tasks"));
}
tasks.push(task);
// store the new array
localStorage.setItem("tasks", JSON.stringify(tasks));
}
// Remove task
function removeTask(e){
// Event Delegation
if (e.target.parentElement.classList.contains('delete-item')){
e.target.parentElement.parentElement.remove();
}
// remove from LocalStorage
removeTaskFromLocalStorage(e.target.parentElement.parentElement);
}
function removeTaskFromLocalStorage(taskItem){
// initialise tasks
let tasks;
// check if tasks is stored in LS
if (localStorage.getItem("tasks")===null){
// if it is not, set tasks array
tasks=[];
// if it is, parse through it
tasks = JSON.parse(localStorage.getItem("tasks"));
}
//loop through the tasks array
// if a task in the array matches the task we want removed --> remove it
tasks.forEach(function(task, index){
// !!!! task is text, taskItem should be text as well
if(task === taskItem.textContent){
// remove 1 task starting from its index
tasks.splice(index,1);
}
})
// store new tasks array
localStorage.setItem("tasks", JSON.stringify(tasks));
}
// filter Tasks
function filterTasks(e){
// compare between tasks in the ul and the input in the filter
const text = e.target.value.toLowerCase();
// console.log(text);
document.querySelectorAll('.list-group-item').forEach(function(task){
// if the filterInput matches a task, show task
// console.log(task);
const item = task.firstChild.textContent;
if(item.toLowerCase().indexOf(text) != -1){
task.classList.add("d-block");
// else hide task
} else {
task.classList.add("d-none");
}
})
}
// Clear Tasks
function clearTasks(e){
// Clear ul
taskList.innerHTML="";
e.preventDefault();
// Clear LocalStorage
clearsTasksFromLocalStorage();
}
// Clear LocalStorage
function clearTasksFromLocalStorage(){
localStorage.clear();
}
One source of data is my favorite concept and DRY
const form = document.querySelector('#task-form');
const taskInput = document.querySelector('#task-input');
const filter = document.querySelector('#filter-tasks')
const taskList = document.querySelector("#task-list");
const clearBtn= document.querySelector("#clear-tasks");
class Tasks {
constructor(taskList) {
this.taskList = taskList;
this.tasks=[];
this.loadTasks();
this.drawTasks();
}
loadTasks(){
const stored = (localStorage.getItem("tasks"));
this.tasks = stored ? JSON.parse(stored) : [];
}
createTaskLI(task){
const li = document.createElement('li');
li.className = 'list-group-item d-flex justify-content-between'
li.appendChild(document.createTextNode(task));
const link = document.createElement('a');
link.className='delete-item';
link.innerHTML = '<i class= "fa fa-remove"></i>';
li.appendChild(link);
this.taskList.appendChild(li);
}
drawTasks() {
this.tasks.forEach((task) => {
this.createTaskLI(task)
})
}
clearTasks = () =>{
this.taskList.innerHTML="";
this.tasks=[];
localStorage.clear();
}
addTask = (e) => {
e.preventDefault()
if(taskInput.value === ""){
alert("Add task");
} else {
this.createTaskLI(taskInput.value)
this.tasks.push(taskInput.value);
this.UpdateLocalStorage();
taskInput.value='';
}
}
removeTask = (e) => {
if (e.target.parentElement.classList.contains('delete-item')){
const item = e.target.parentElement.parentElement;
const parent = item.parentElement;
const index = [...parent.children].indexOf(item);
item.remove();
this.tasks.splice(index, 1);
this.UpdateLocalStorage();
}
}
UpdateLocalStorage(){
localStorage.setItem("tasks", JSON.stringify(this.tasks));
}
filterTasks = (e) => {
const text = e.target.value.toLowerCase();
document.querySelectorAll('.list-group-item')
.forEach((task, index) => {
const condition = (text === "" || this.tasks[index].includes(text))
task.classList.add(condition ? "d-flex" : "d-none");
task.classList.remove(condition ? 'd-none': "d-flex");
})
}
}
const tasks = new Tasks(taskList);
loadEventListeners();
function loadEventListeners(){
form.addEventListener('submit', tasks.addTask);
taskList.addEventListener('click', tasks.removeTask );
filter.addEventListener('keyup', tasks.filterTasks);
clearBtn.addEventListener('click', tasks.clearTasks)
}
The function filterTasks adds classes but doesn't remove it. You have to remove classes
if(item.toLowerCase().indexOf(text) != -1){
task.classList.remove("d-none");
task.classList.add("d-block");
// else hide task
} else {
task.classList.remove("d-block");
task.classList.add("d-none");
}
Probably classList.toggle works even better.
I finally made it work
function filterTasks(e){
// Compare betweeen tasks in the ul and the input in the filter
const text = e.target.value.toLowerCase();
// Select all the lis and loop through them
document.querySelectorAll('.list-group-item').forEach(function(task){
const item = task.firstChild.textContent;
console.log(task);
// If the filterInput matches a task, show task
if(item.toLocaleLowerCase().indexOf(text) != -1){
task.className = "list-group-item d-flex justify-content-between";
} else {
// else, hide task
task.classList.remove("d-flex");
task.classList.add("d-none");
}
})
e.preventDefault();
}
I'm trying to implement a searchbar to search adresses and show the selected place on a map.
When I type in the searchbar the results are showing in a dropdown, now I want to edit my map and other stuff when I click on a result.
But I can't manage to add a listener to the elements (which are dynamically created when I got the results of the search), no matter what I try (addEventListener, JQuery, href) when I inspect the elements on my browser no listener is attached to any of them.
Here is my html :
<div class="container p-3 text-center text-md-left clearfix">
<h1>Smart-bornes</h1>
<p>Je localise les smart-bornes les plus proches</p>
<div class="input-group dropdown mx-auto w-75 float-md-left">
<input id="localisation_barreRecherche" class="form-control" type="text" placeholder="Rechercher un lieu"/>
<button id="localisation_boutonRecherche" class="btn btn-light">Rechercher</button>
<div id="localisation_dropdownRecherche" class="dropdown-menu w-100"></div>
</div>
</div>
<div class="container p-3">
<div id="map"></div>
</div>
And my JS:
function initBarreRecherche(){
let barreRecherche = document.getElementById('localisation_barreRecherche');
let boutonRecherche = document.getElementById('localisation_boutonRecherche');
let dropdownResultats = document.getElementById('localisation_dropdownRecherche');
barreRecherche.onkeyup = function (event) {
console.log('onkeyup');
if(event.key === 'Enter'){
}else if(event.key === 'keydown'){
}else if(barreRecherche.value !== '') {
rechercheAdr(barreRecherche.value);
$(dropdownResultats).show();
}else{
$(dropdownResultats).hide();
}
};
boutonRecherche.onclick = function () {
}
}
function rechercheAdr(entree){
console.log('recherche');
return new Promise((resolve, reject) => {
fetch(rechercheURL + entree)
.then(resp => {
return resp.text();
})
.then(adressesJSON => {
let adresses = JSON.parse(adressesJSON);
let dropdownResultats = document.getElementById('localisation_dropdownRecherche');
//dropdownResultats.style.width = '100%';
dropdownResultats.style.zIndex = '10000';
let resultats = document.createElement('ul');
resultats.className = 'list-group';
if(adresses.length > 0){
for(let [key, adr] of Object.entries(adresses)){
let result = document.createElement('li');
result.className = 'list-group-item list-group-item-action';
result.href = 'javascript : resultOnClick(adr)';
result.style.paddingLeft = '5px';
result.style.paddingRight = '5px';
result.style.cursor = 'pointer';
//result.style.overflow = 'hidden';
result.innerText = adr.display_name;
result.addEventListener('click', () => console.log('onclick'));
resultats.appendChild(result);
}
}else{
console.log('aucun résultat');
let msgAucunResultat = document.createElement('li');
msgAucunResultat.style.paddingLeft = '5px';
msgAucunResultat.style.paddingRight = '5px';
msgAucunResultat.innerText = 'Aucun résultat';
resultats.appendChild(msgAucunResultat);
}
dropdownResultats.innerHTML = resultats.innerHTML;
console.log(adresses)
})
})
}
manually call initBarreRecherche() at the end of response.
.then(adressesJSON => {
///....
this.initBarreRecherche()
})
You are using jquery so instead of all 'onClick' syntax, or addEventListener, you can attach click handler like:
$(dropdownResultats).on('click', 'li', event => {
alert('some li clicked')
})
I want to add a category/restaurant to my drop down menu by typing a value into an input field. As you can see in my code, I am not using the <select> and <option>. When I add my JS code it gets an error:
TypeError: newRestaurant.add is not a function.
But when I changed the tags to <select> and <option> my JS code with the add() method worked.
<div class="dropdown">
<button class="locationSetter">WHERE ARE YOU?</button>
<ul class="dropdown-content">
<li><span>1</span></li>
<li><span>2</span></li>
<li><span>3</span></li>
<li><span>4</span></li>
<li><span>5</span></li>
<li><span>6</span></li>
<li><span>7</span></li>
</ul>
</div>
JS
// Drop Down function and adding the chosen location to the location setter
const locationSetter = document.querySelector('.locationSetter');
const dropdownContent = document.querySelector('.dropdown-content');
const locations = document.querySelector('span');
dropdownContent.addEventListener('click', e => {
if (e.target.tagName === 'SPAN') {
locationSetter.textContent = e.target.innerHTML;
locationSetter.style.color = 'blue';
locationSetter.style.fontSize = '18px';
}
});
// Adding a restaurant to the drop down menu
const addRestaurantInput = document.querySelector('.addRestaurantInput');
const restaurantListGenerator = newRestaurant => {
const html = `<li><span>${newRestaurant}</span></li>`;
//dropdownContent.innerHTML += html;
}
addRestaurantInput.addEventListener('submit', e => {
e.preventDefault();
const newRestaurant = addRestaurantInput.addnew.value.trim();
let option = document.createElement('span');
option.text = newRestaurant;
dropdownContent.add(option, dropdownContent[0]);
if (addRestaurantInput.length) {
restaurantListGenerator(addRestaurantInput);
addRestaurantInput.reset();
}
})
I would like to figure out if I can make the JS code work and I can add a restaurant/ value which has been typed into the input field using <ul> and <li> tag.
Currently I only work in Vanilla JS.
Any advice much appreciated.
Thanks!
<html>
<body>
<div class="dropdown">
<button class="locationSetter">WHERE ARE YOU?</button>
<input type="text" class="addRestaurantInput"/>
<ul class="dropdown-content">
<li><span>1</span></li>
<li><span>2</span></li>
<li><span>3</span></li>
<li><span>4</span></li>
<li><span>5</span></li>
<li><span>6</span></li>
<li><span>7</span></li>
</ul>
</div>
</body>
<script>
const locationSetter = document.querySelector('.locationSetter');
const dropdownContent = document.querySelector('.dropdown-content');
const locations = document.querySelector('span');
dropdownContent.addEventListener('click', e => {
if (e.target.tagName === 'SPAN') {
locationSetter.textContent = e.target.innerHTML;
locationSetter.style.color = 'blue';
locationSetter.style.fontSize = '18px';
}
});
// Adding a restaurant to the drop down menu
const addRestaurantInput = document.querySelector('.addRestaurantInput');
//const restaurantListGenerator = newRestaurant => {
// const html = `<li><span>${newRestaurant}</span></li>`;
//dropdownContent.innerHTML += html;
//}
addRestaurantInput.addEventListener('change', e => {
e.preventDefault();
const newRestaurant = e.target.value;
let elem = document.createElement("LI");
let span = document.createElement("SPAN");
let text = document.createTextNode(newRestaurant.toString());
span.appendChild(text);
elem.appendChild(span);
dropdownContent.appendChild(elem);
})
</script>
</html>
You just have to append the child in the ul element just by getting value from element when the input value is change.Just enter the value in input and press enter. It will append the value in list.
Hope this helps!!!