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>
Related
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}`)
}
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();
});
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>
I'm trying to create a chain of buttons:
First options;
- Button 1
- Button 2
IF chosen Button 1:
- Button 1a
- Button 1b
IF chosen Button 1a:
- Button 1aa
- Button 1ab
IF chosen Button 1b:
- Button 1ba
- Button 1bb
And so on.. same goes for Button 2.
Thus far I got this but my .js is not working out for me.
I tried it in two ways.
WAY 1:
HTML (onclick="nextPush" is going to change in way 2)
<div class="buttons1-2">
<button id="btn1" class="btn btn1" onclick="buttonPushed(this)">Button 1</button>
<button id="btn2" class="btn btn2" onclick="buttonPushed(this)">Button 2</button>
</div>
<div class="buttons1a-b">
<button id="btn1a" class="btn btn1a" onclick="nextPush(this)">Button 1a</button>
<button id="btn1b" class="btn btn1b" onclick="nextPush(this)">Button 1b</button>
</div>
<div class="buttons2a-b">
<button id="btn2a" class="btn btn2a">Button 2a</button>
<button id="btn2b" class="btn btn2b">Button 2b</button>
</div>
<div class="buttons1aa-ab">
<button id="btn1aa" class="btn btn1a">Button 1aa</button>
<button id="btn1ab" class="btn btn1b">Button 1ab</button>
</div>
<div class="buttons1ba-bb">
<button id="btn1ba" class="btn btn2a">Button 1ba</button>
<button id="btn1bb" class="btn btn2b">Button 1bb</button>
</div>
WAY 1: .JS
function buttonPushed(btn) {
var replacewith = "buttons1a-b";
if (btn.id == "btn2") {
replacewith = "buttons2a-b";
}
function nextPush(btn) {
var replacewith = "buttons1aa-ab";
if (btn.id == "btn1b") {
replacewith = "buttons1ba-bb";
}
var allChildren = document.getElementsByClassName('buttons')[0].children;
for (var i = 0; i < allChildren.length; i++) {
var child = allChildren[i];
if (child.className != replacewith) {
child.style.display = "none";
} else {
child.style.display = "inline";
}
}
}
WAY 2: HTML (notice the onclick="nextPush" is gone)
<div class="buttons1-2">
<button id="btn1" class="btn btn1" onclick="buttonPushed(this)">Button 1</button>
<button id="btn2" class="btn btn2" onclick="buttonPushed(this)">Button 2</button>
</div>
<div class="buttons1a-b">
<button id="btn1a" class="btn btn1a" onclick="buttonPushed(this)">Button 1a</button>
<button id="btn1b" class="btn btn1b" onclick="buttonPushed(this)">Button 1b</button>
</div>
<div class="buttons2a-b">
<button id="btn2a" class="btn btn2a">Button 2a</button>
<button id="btn2b" class="btn btn2b">Button 2b</button>
</div>
<div class="buttons1aa-ab">
<button id="btn1aa" class="btn btn1a">Button 1aa</button>
<button id="btn1ab" class="btn btn1b">Button 1ab</button>
</div>
<div class="buttons1ba-bb">
<button id="btn1ba" class="btn btn2a">Button 1ba</button>
<button id="btn1bb" class="btn btn2b">Button 1bb</button>
</div>
WAY 2 .JS
function buttonPushed(btn) {
/* btn = Id: btn1, btn2, btn1a or btn1b */
let replacewith = "buttons1a-b";
if (btn.id == "btn2") {
replacewith = "buttons2a-b";
}
else if (btn.id == "btn1a") {
replacewith = "buttons1aa-ab";
}
else if (btn.id == "btn1b") {
replacewith = "buttons1ba-bb";
}
}
let allChildren = document.getElementsByClassName('buttons')[0].children;
for (let i = 0; i < allChildren.length; i++) {
let child = allChildren[i];
if (child.className != replacewith) {
child.style.display = "none";
} else {
child.style.display = "inline";
}
}
.CSS for BOTH WAYS:
.buttons1a-b {
display: none;
}
.buttons2a-b {
display: none;
}
.buttons1aa-ab {
display: none;
}
.buttons1ba-bb {
display: none;
}
Sorry for the long post, hope you can help me out :) If you know a better way to do this, please also do let me know.
Building on your example, and the one from Michael, you could also use another approach of declaring what div you want displayed by attaching an attribute to the button, and then add an event listener to all buttons with that attribute. This makes the HTML slightly smaller and more declarative, and makes it easier to switch what element you want to display next instead of relying on a particular schema of id's.
(function(document) {
// get all buttons that have the attribute data-next
const buttons = document.querySelectorAll('[data-next]');
for (const item of buttons) {
// get references to the parent item and next item to hide/show
const parentId = item.getAttribute('data-parent');
const parent = document.querySelector(`#${parentId}`);
const nextDivId = item.getAttribute('data-next');
const nextDiv = document.querySelector(`#${nextDivId}`);
if (!nextDiv) {
console.error('could not find next div for button ', item);
}
// attach an event listener for click that toggles visibility of the above elements
item.addEventListener('click', function() {
nextDiv.classList.toggle('hidden');
parent.classList.toggle('hidden');
});
}
})(document);
.hidden {
display: none;
}
<div id="base">
<button data-next="option-a" data-parent="base">Option A</button>
<button data-next="option-b" data-parent="base">Option B</button>
</div>
<div id="option-a" class="hidden">
<p>Option A</p>
</div>
<div id="option-b" class="hidden">
<p>Option B</p>
</div>
If you want to add new buttons dynamically (or change what your next items should be) you will need to attach the event listener when you create your other buttons. For instance, you can do something like the following:
(function(document) {
function onButtonClicked(event) {
const item = event.target;
// get references to the next item to show
const nextDivId = item.getAttribute('data-next');
const nextDiv = document.querySelector(`#${nextDivId}`);
if (!nextDiv) {
console.error('could not find next div for button ', item);
}
// The function toggle on classList either removes a class if it exists
// or adds it if it does not exist in the list of classes on the element
nextDiv.classList.toggle('hidden');
// check if container has an attribute for loading next buttons lazily
const lazyLoadLevel = nextDiv.getAttribute('data-level');
// if we found the attribute, load the contents
if (lazyLoadLevel) {
// cast lazyLoadedLevel to an integer (with +) since getAttribute returns a string
loadLevel(+lazyLoadLevel, nextDiv);
// since we have populated the container we can remove the attribute so that elements do not get added again
nextDiv.removeAttribute('data-level');
}
// get references to the parent item to hide
const parentId = item.getAttribute('data-parent');
const parent = document.querySelector(`#${parentId}`);
if (parent) {
parent.classList.toggle('hidden');
}
}
function addButton(parent, nextElementId, text) {
const newItem = document.createElement('button');
newItem.setAttribute('data-next', nextElementId);
newItem.setAttribute('data-parent', parent.getAttribute('id'));
newItem.textContent = text;
newItem.addEventListener('click', onButtonClicked);
parent.appendChild(newItem);
}
function loadLevel(level, container) {
switch (level) {
// depending on level you can define other buttons to add here
case 2:
{
addButton(container, 'option-a', 'Goto option a');
break;
}
}
}
// get all *existing* buttons that have the attribute data-next
// this is run once when the script loads, and will not attach listeners to dynamically created buttons
const buttons = document.querySelectorAll('[data-next]');
for (const item of buttons) {
// attach an event listener for click that toggles visibility of parent and next elements
// notice that we pass a reference to onButtonClicked. Even though it is a function we shouldn't call it *here*
item.addEventListener('click', onButtonClicked);
}
})(document);
.hidden {
display: none;
}
<div id="base">
<button data-next="option-a" data-parent="base">Option A</button>
<button data-next="option-b" data-parent="base">Option B</button>
</div>
<div id="option-a" class="hidden">
<p>Option A</p>
<button data-next="option-b" data-parent="option-a">Option B</button>
</div>
<div id="option-b" class="hidden" data-level="2">
<p>Option B. The contents of this div is loaded lazily based on the value of the attribute data-level</p>
</div>
At first, I was thinking this should be done entirely dynamically -- where the next container of buttons is created and inserted into the DOM when the button is clicked. But judging by your current attempts, it seems like you want to have all the buttons hardcoded into the source, hidden with CSS, and shown with DOM during the click event. Here is one way you can achieve that:
function handleButtonClick(button) {
const clickedID = button.id.substring(3);
const nextDiv = document.getElementById("buttons" + clickedID);
if (nextDiv) {
nextDiv.style.display = "block";
}
}
.hidden {
display: none;
}
<div id="buttons">
<button id="btn1" onclick="handleButtonClick(this)">Button 1</button>
<button id="btn2" onclick="handleButtonClick(this)">Button 2</button>
</div>
<div id="buttons1" class="hidden">
<button id="btn1a" onclick="handleButtonClick(this)">Button 1a</button>
<button id="btn1b" onclick="handleButtonClick(this)">Button 1b</button>
</div>
<div id="buttons2" class="hidden">
<button id="btn2a" onclick="handleButtonClick(this)">Button 2a</button>
<button id="btn2b" onclick="handleButtonClick(this)">Button 2b</button>
</div>
<div id="buttons1a" class="hidden">
<button id="btn1aa" onclick="handleButtonClick(this)">Button 1aa</button>
<button id="btn1ab" onclick="handleButtonClick(this)">Button 1ab</button>
</div>
<div id="buttons1b" class="hidden">
<button id="btn1ba" onclick="handleButtonClick(this)">Button 1ba</button>
<button id="btn1bb" onclick="handleButtonClick(this)">Button 1bb</button>
</div>
<div id="buttons2a" class="hidden">
<button id="btn2aa" onclick="handleButtonClick(this)">Button 2aa</button>
<button id="btn2ab" onclick="handleButtonClick(this)">Button 2ab</button>
</div>
<div id="buttons2b" class="hidden">
<button id="btn2ba" onclick="handleButtonClick(this)">Button 2ba</button>
<button id="btn2bb" onclick="handleButtonClick(this)">Button 21bb</button>
</div>
This just identifies which button was clicked, and uses that information to determine the next div to show, until there are no more divs that correspond to the one that was clicked.
I'm using a bootstrap modal.
The Function what I want to dynamically create a button at body tag when I click the modal button.
Description about function what I apply: As soon as I click the bluebutton, I want to create it at the body tag('beside the '+' button')
window.onlaod = function(){
var blue = document.getElementById('blue');
blue.onclick = function(){
blue.onclick = null;
var result = document.getElementById('result');
var newblue = document.createElement('span');
newblue.id = 'newblue';
newblue.innerHTML += '<button type="button" class="btn btn-primary btnWH " id="blue"></button>';
result.appendChild(newblue);
};
};
-> This is the code about event after click the bluebutton.
<!-- label color -->
<div class="modal-body">
<button type="button" class="btn btn-primary btnWH " id="blue"></button>
</div>
-> This is the code about bluebutton.
<div class="card border-secondary mb-3" style="max-width: 20rem;">
<div class="card-header">Header</div>
<div class="card-body">
<div id="result">
<span id="first">
<button type="button" class="btn btn-primary plusbtn" data-toggle="modal" data-target="#mymodal"> +
</button>
</span>
</div>
</div>
</div>
-> This is the code about '+'button.
This will create a button when click on add button inside div id of result code as follows:
<html>
<body>
<button type="button" id="blue">add</button>
<div id="result"></div>
<script>
window.onload = function() {
return addEvent();
}
function addEvent() {
var blueButton = document.getElementById('blue');
blueButton.addEventListener("click", addButton)
}
function addButton() {
var result = document.getElementById('result');
var newBtn = document.createElement('span');
newBtn.id = 'newblue';
newBtn.innerHTML += '<button type="button" id="blue">test</button>';
result.appendChild(newBtn);
}
</script>
</body>
</html>