How to dynamically change ID attribute using Vanilla JavaScript - javascript

I am currently building a to-do list app.
I am using the insertAdjacentHTML method to add new items to the list and that works just fine. My problem remains on how to dynamically change the id attribute that it begins to increase by 1 as I add a new item to the list.
How can I solve that?
Here is the code:
function addTaskFunc() {
const aTask = `
<div class="task" id="task-0">
<button class="done__btn">
<i class="far fa-check-square"></i>
</button>
<p>${box.value}</p>
<button class="priority">Make priority</button>
<button class="cancel__btn">
<i class="far fa-times-circle"></i>
</button>
</div>
`;
const x = box.value;
taskList.insertAdjacentHTML('afterbegin', aTask);
box.value = '';
}
newTask.addEventListener('click', addTaskFunc);

Add a counter (idCounter) and use it in the template literal, and increment it whenever you use it:
let idCounter = 0;
function addTaskFunc() {
const aTask = `
<div class="task" id="task-${idCounter++}">
<button class="done__btn">
<i class="far fa-check-square"></i>
</button>
<p>${box.value}</p>
<button class="priority">Make priority</button>
<button class="cancel__btn">
<i class="far fa-times-circle"></i>
</button>
</div>
`;
const x = box.value;
taskList.insertAdjacentHTML('afterbegin', aTask);
box.value = '';
}

You can use a variable that increments every time a new task is added.
This approach is slightly different because it provides a TaskBuilder constructor, this is only to avoid global variables and potential clashes with other scripts.
function TaskBuilder() {
if (!new.target) {
throw new Error("Illegal argument error, you should call this function as a constructor.");
}
this.currentId = 0;
}
TaskBuilder.prototype.addTask = function() {
const aTask = `
<div class="task" id="task-${this.currentId}">
<button class="done__btn">
<i class="far fa-check-square"></i>
</button>
<p>${box.value}</p>
<button class="priority">Make priority</button>
<button class="cancel__btn">
<i class="far fa-times-circle"></i>
</button>
</div>
`;
const x = box.value;
taskList.insertAdjacentHTML('afterbegin', aTask);
box.value = '';
this.currentId++;
};
const taskBuilder = new TaskBuilder();
newTask.addEventListener('click', function() {
taskBuilder.addTask();
});

Related

DOM traversal - Siblings is not selected when editing element - JavaScript

When I use below code, the console.log in edit element function gives me #text but when I wrap the buttons in the div, container in the add element function and use e.target.parentElement.previousElementSibling. In this case it works fine, but I don't want to use wrap.
My goal is just to select the <p class="title">{todoInput.value}</p> when editing
function editItem(e) {
const item = e.target;
let element = e.target.previousElementSibling;
console.log(element, "element");
todoInput.value = element.innerHTML;
}
function addItem(event) {
event.preventDefault();
const value = todoInput.value;
if (value !== "") {
const todoDiv = document.createElement("div");
todoDiv.classList.add("todo");
todoDiv.innerHTML = `<p class="title">${todoInput.value}</p><button type="button" class="completeBtn">
<i class="fas fa-check"></i>
</button>
<!-- delete btn -->
<button type="button" class="trashbtn">
<i class="fas fa-trash"></i></button>
<button type="button" class="editBtn">
<i class="fas fa-edit"></i>
</button>`;
<div class="todo-container">
<div class="todo-list"></div>
<button class="clear-btn">Clear Items</button>
</div>
I am getting #text in console.log. Any idea?
const todoList = document.querySelector('.todo-list');
function addItem(event) {
event.preventDefault();
const value = todoInput.value;
if (value !== "") {
const todoDiv = document.createElement("div");
todoDiv.classList.add("todo");
todoDiv.innerHTML = `<p class="title">${todoInput.value}</p>
<button type="button" class="completeBtn">
<i class="fas fa-check"></i>
</button>
<!-- delete btn -->
<button type="button" class="trashbtn">
<i class="fas fa-trash"></i></button>
<button type="button" class="editBtn">
<i class="fas fa-edit"></i>
</button>`;
todoList.appendChild(todoDiv);
}
//event listeners
todoBtn.addEventListener("click", addItem);
todoList.addEventListener('click', editItem);
function editItem(e) {
const item = e.target;
let element = e.target.previousSibling;
console.log(element, "element");
todoInput.value = element.innerHTML;
}
<div class="todo-container">
<div class="todo-list"></div>
<button class="clear-btn">Clear Items</button>
</div>

addEventListener for click is not working

const renderNote = data => {
const postListRef = ref(db, 'Notes/' +data.key);
console.log(data.key)
const newPostRef = push(postListRef);
var status = 'Pending'
var title = 'new note'
var date = '29-4-2022'
var note = 'newly added note'
let card =
`<div id="single-card" class="col-lg-4 col-md-3" data-id=${data.key} ><!--outer layer of single card-->
<div class="card card-body"><!--card body-->
<p class="badge" id="status" style="background-color: rgb(0, 81, 81);">${status}</p>
<span class="side-stick"></span> <!--side-stick color-->
<!-- note title -->
<h5 class="note-title text-truncate w-75 mb-0" >${title}<i class="point fa fa-circle ml-1 font-10"></i></h5><!--fa fa-circle is for the dot dot dot(continuity)-->
<p class="note-date font-12 text-muted mt-0">${date}</p>
<!--note description-->
<div class="note-content">
<p class="note-inner-content text-muted" >${note}<i class="point fa fa-circle ml-1 font-10"></i></p>
</div>
<button class="btn btn-del">Delete${data.key}</button>
<div id="actions" >
</div>
</div>
</div>`
prod.innerHTML += card;
const btnDelete = document.querySelector(`[data-id='${data.key}'] .btn-del`);
console.log(btnDelete);
btnDelete.addEventListener("click",()=>{
console.log('deleting');
});
}
EventListener is not working. But when I print the btnDelete(console.log(btnDelete);) it is printing correctly. But the eventlistener is not workingDoes anybody know what is wrong with the code?
Why donĀ“t you use onclick in HTML?
<button onclick="console.log('deleting');" class="btn btn-del">Delete${data.key}</button>
You can even call a delete Function like that:
HTML:
<button onclick="deleteCard(${data.key})" class="btn btn-del">Delete${data.key}</button>
JavaScript:
function deleteCard(key) {
console.log(`Delete Card with key: ${key}`)
}

Why does the addEventListener property does not work on a dynamic HTMLcollection object?

I am working on a chrome extension and trying to add an event listener to a getElementsByClassName variable, in which elements are added dynamically using template strings.
I have tried a lot of changes in the code, but the code doesn't work.
The code is supposed to delete the targeted element from the array "recipeList", storing the array in localStorage and then render the updated array "recipeList" using template string to the HTML code again.
DELETE BUTTON Function
let delBtn = document.getElementsByClassName("del-btn");
for(let i = 0; i < delBtn.length; i++) {
delBtn[i].addEventListener("click", function() {
recipeList.splice(i, 1);
localStorage.setItem("recipeList", JSON.stringify(recipeList));
recipeList = JSON.parse(localStorage.getItem("recipeList"));
render(recipeList);
if(!recipeList.length) {
tabBtn.style.width = "100%";
delAllBtn.style.display = "none";
}
});
}
RENDER CODE
function render(list) {
let recipeURL = "";
for(let i = 0; i < list.length; i++) {
recipeURL += `
<div class="mb-2 row">
<div class="col-1 num-btn">
${i+1}
</div>
<div class="col-10">
<div class="recipe-url">
<a target="_blank" href="${list[i]}">
${list[i]}
</a>
</div>
</div>
<div class="col-1 del-btn">
<a href="#">
<i class="bi bi-trash-fill"></i>
</a>
</div>
</div>
`
}
urlList.innerHTML = recipeURL;
console.log(delBtn);
}
When you render, you create new .del-btn which are not included in your first let delBtn = document.getElementsByClassName("del-btn");.
Each time you create new .del-btn, you should also add a new listener.
function render(list) {
let recipeURL = "";
for(let i = 0; i < list.length; i++) {
recipeURL += `
<div class="mb-2 row">
<div class="col-1 num-btn">
${i+1}
</div>
<div class="col-10">
<div class="recipe-url">
<a target="_blank" href="${list[i]}">
${list[i]}
</a>
</div>
</div>
<div class="col-1 del-btn">
<a href="#">
<i class="bi bi-trash-fill"></i>
</a>
</div>
</div>
`
}
urlList.innerHTML = recipeURL;
console.log(delBtn);
Array.from(urlList.querySelectorAll('.del-btn')).forEach((btn, i) => {
btn.addEventListener('click', () => console.log('.del-btn index: ' + i))
})
}
}

problem in #click event which adding one more fontawesome icon

i tried to make responsive navigation with vue js, when i tried to add '#click' to toggle burger bar or close icon, but it's adding the 'close' icon instead every time i click it.
here's the code
template section
<template>
// ----
<button #click="toggleButton">
<i v-if="!toggle" class="fas fa-bars"></i>
<i v-if="!toggleClose" class="fas fa-times"></i>
</button>
// ----
</template>
script section
<script>
export default {
name: "MultiNav",
data: function() {
return {
toggle: false,
toggleClose: true
};
},
methods: {
toggleButton() {
this.toggle = !this.toggle;
this.toggleClose = !this.toggleClose;
}
}
};
</script>
pict :
i try to use :
<button #click="toggle = ! toggle">
<i v-if="!toggle" class="fas fa-bars"></i>
<i v-if="toggle" class="fas fa-times"></i>
</button>
it still resulting the same result
You need to add a key to the icons.
<button #click="toggle = ! toggle">
<i v-if="!toggle" key="bars" class="fas fa-bars"></i>
<i v-if="toggle" key="times" class="fas fa-times"></i>
</button>
The key will tell Vue's algorithm that the icons are in fact different elements. Without that the virtual dom representation thinks that they are the same element.
Try switching the classes using condition
<button #click="toggle = ! toggle">
<i class="fas" :class="toggle?'fa-times':'fa-bars'"></i>
</button>

Why click event works after two clicks VANILLA

I am trying to trigger a function through a event listener with only one click.
But it occurs after two click (in the first time) if I don't do F5 its trigger after one click.
Code:
HTML
<div class="main-header-navbar">
....
<span class="main-header-navbar-right-icons">
<i class="fas fa-search header-icon"></i>
<i class="fas fa-plus header-icon"></i>
</span>
</div>
JS
const ADD_FORM_BUTTON = document.querySelector(".fa-plus");
ADD_FORM_BUTTON.addEventListener("click", function (event) {
event.preventDefault();
if (ADD_FORM.style.display === "none") {
ADD_FORM.style.display = "flex";
} else ADD_FORM.style.display = "none";
});
What am I missing?
You probably need to add style="display: none;" to your ADD_FORM so that it's initially hidden, then when you click on the fa-plus it will display it. See the snippet below:
const ADD_FORM_BUTTON = document.querySelector(".fa-plus");
const ADD_FORM = document.getElementById("form");
ADD_FORM_BUTTON.addEventListener("click", function(event) {
event.preventDefault();
if (ADD_FORM.style.display === "none") {
ADD_FORM.style.display = "flex";
} else {
ADD_FORM.style.display = "none"
};
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css" rel="stylesheet" />
<div class="main-header-navbar">
<span class="main-header-navbar-right-icons">
<i class="fas fa-search header-icon"></i>
<i class="fas fa-plus header-icon"></i>
</span>
<div id="form" style="display: none;">ADD_FORM</div>
</div>

Categories