Reputation: 41
guys i want to add one class to li Element aftet it is created through insertAdjacentHTML but i dont know how i can select it in fact i replaced insertAdjacentHTML way with append that i commented appen way; my codes are:
function todosGenerator(todosList) {
todoListElem.innerHTML = ''
// let newTodoLiElem, newTodoLabalElem, newTodoCompleteBtn, newTodoDeleteBtn
todosList.forEach(function (todo) {
// console.log(todo);
// newTodoLiElem = $.createElement('li')
// newTodoLiElem.className = 'completed well'
// newTodoLabalElem = $.createElement('label')
// newTodoLabalElem.innerHTML = todo.title
// newTodoCompleteBtn = $.createElement('button')
// newTodoCompleteBtn.className = 'btn btn-success'
// newTodoCompleteBtn.innerHTML = 'Complete'
// newTodoCompleteBtn.setAttribute('onclick', 'editTodo(' + todo.id + ')')
// newTodoDeleteBtn = $.createElement('button')
// newTodoDeleteBtn.className = 'btn btn-danger'
// newTodoDeleteBtn.innerHTML = 'Delete'
// newTodoDeleteBtn.setAttribute('onclick', 'removeTodo(' + todo.id + ')')
// if (todo.complete) {
// newTodoLiElem.className = 'uncompleted well'
// newTodoCompleteBtn.innerHTML = 'UnComplete'
// } **/! ican not write these lines with insertAdjacentHTML**
// newTodoLiElem.append(newTodoLabalElem, newTodoCompleteBtn, newTodoDeleteBtn)
// todoListElem.append(newTodoLiElem)
todoListElem.insertAdjacentHTML('beforeend','<li class="completed well is"><label>'+todo.title+'</label><button class="btn btn-success" onclick="editTodo('+todo.id+')">Complete</button><button class="btn btn-danger" onclick="removeTodo('+todo.id+')">Delete</button></li>')
})
}
Upvotes: 2
Views: 702
Reputation: 4710
I think your commented code is better, but if you want to stick with the insertAdjacentHTML
, you can alter to something like this:
var liClass, cBtnInner;
if (todo.complete) {
liClass = 'uncompleted well';
cBtnInner = 'UnComplete';
} else {
liClass = 'completed well is';
cBtnInner = 'Complete';
}
todoListElem.insertAdjacentHTML(
'beforeend',
'<li class="' + liClass + '"><label>' + todo.title +
'</label><button class="btn btn-success" onclick="editTodo(' +
todo.id + ')">' + cBtnInner +
'</button><button class="btn btn-danger" onclick="removeTodo(' +
todo.id + ')">Delete</button></li>'
);
Upvotes: 1
Reputation: 43880
First off, do not use inline event handlers (see Why are inline event handler attributes a bad idea in modern semantic HTML?). Secondly, if you are dynamically adding buttons that trigger an event handler (a function that runs when an event is triggered like a "click" event), use event delegation by registering events to a common ancestor element.
In the example below, only the elements are generated and added to the DOM -- there is no event binding. A <form>
is wrapped around the <ol>
so that the succinct syntax of the HTMLFormElement interface can be used should it be needed (in this example it's used once ie const main = document.forms[0]
, but it can do a lot more with less code). See event handling for details as well.
Details are commented in example
const todo = [{
title: "First task",
status: "pending"
}, {
title: "Second task",
status: "pending"
}, {
title: "Third task",
status: "complete"
}, {
title: "Fourth task",
status: "pending"
}, {
title: "Fifth task",
status: "complete"
}];
/**
* Generates a list from a given array of objects
* 1. Adds a <ol> within a <form>
* 2. Adds an <li> to <ol> for each object in >list<
* 3. Within each <li> is an <output> and 2 <button>s
* 4. Each object's "title" is the text of <output>
* 5. Each object's "status" is the className of <li>
* @param {array<object>} list - Each object is the following by default:
* {title: "TBA", status: "pending"}
* @param {string||object} node - If it's a string then it's a selector of an element. Otherwise it's a
* DOM object. If undefined it is a @defualt of a selector called "body"
*/
function genList(list, node = "body") {
let root = typeof node === "string" ? document.querySelector(node) : node;
const form = document.createElement('form');
const ol = document.createElement('ol');
root.append(form);
form.append(ol);
list.forEach((item, index) => {
ol.insertAdjacentHTML('beforeend', `<li class="${item.status}"><output name="title">${item.title}</output> <button name="complete" class="btn btn-success" type="button"></button><button name="delete" class="btn btn-danger" type="button">Delete</button></li>`);
});
}
// Call genList pass the >todo< array and do not define second @param so it'll just add to <body>
genList(todo);
// Reference the <form>
const main = document.forms[0];
// Register the click event to <form> -- call action(event) when click event is triggered on <form>
main.onclick = action;
// Event handler passes Event object by default
function action(event) {
// Reference the element the user clicked
const clk = event.target;
/*
If the user clicked an element with [name="complete"]...
...toggle the classNames "complete" and "pending" on it's parent element
In other words: if <button name="complete"...> was clicked...
...reverse the className of the containing <li> from/to "complete"/"pending"
*/
if (clk.name === "complete") {
clk.parentElement.classList.toggle("complete");
clk.parentElement.classList.toggle("pending");
return;
}
/*
If the user clicked an element with [name="delete"]...
...find it's parent element and remove it
*/
if (clk.name === "delete") {
return clk.parentElement.remove();
}
}
output {
display: inline-block;
width: 25ch;
}
button {
display: inline-block;
width: 12ch;
}
.complete output {
text-decoration: line-through red;
}
.complete .btn-success::before {
content: "Completed";
}
.pending .btn-success::before {
content: "Complete";
}
Upvotes: 2