i am in a bit of a pickle.
I am trying to get a button to delete its parent when clicked.
But when i run the code it won't respond. in fact , it doesn't delete anything at all.
I have specified that IF() event.target === deleteButton{ remove parent}
but it either doesn't recognise the event, or it fails to find the parent.
a bit of help would be greatly apreciated!
I
const todoListElement = document.getElementById('ordered-todo-list');
const form = document.getElementById('todo-form');
const deleteButton = document.querySelector('.delete');
todoListElement?.addEventListener("click", todoListEraser)
function todoListEraser( event:MouseEvent) {
console.log(event.target)
if (event.target === deleteButton ){
(event.target as HTMLElement).closest('li')?.remove();
}
else {
return console.log('did not work, try again');
}
}
<template id="list-item-template">
<li class="list-item">
<input type="checkbox" class="status-toggle" name="form-checkbox">
<p class="task-text"></p>
<button class="delete" >X</button>
</li>
</template>
<ol id="ordered-todo-list">
</ol>
am working in typescript.
My answer might be completely wrong for what you need, but this doesn't seem to be your complete code so I had to take some guesses.
There are two ways I can see this being done. If the <li> elements in your template are added to the list before this JavaScript executes, you can use the first method (commented out). If the <li> elements from your template are added after this JavaScript executes, the second method should work just fine.
/*
// Method 1
document.querySelectorAll(".delete").forEach(el => {
el.addEventListener("click", e => {
e.target.parentElement.remove();
});
});
*/
// Method 2
document.querySelector("#ordered-todo-list").addEventListener("click", e=> {
if(e.target.className.includes("delete")) {
e.target.parentElement.remove();
}
});
<ol id="ordered-todo-list">
<li class="list-item">
<input type="checkbox" class="status-toggle" name="form-checkbox">
<p class="task-text"></p>
<button class="delete" >X</button>
</li>
<li class="list-item">
<input type="checkbox" class="status-toggle" name="form-checkbox">
<p class="task-text"></p>
<button class="delete" >X</button>
</li>
<li class="list-item">
<input type="checkbox" class="status-toggle" name="form-checkbox">
<p class="task-text"></p>
<button class="delete" >X</button>
</li>
</ol>
Method 1 adds event listeners to the delete buttons themselves. Then it simply removes the parentElement.
Method 2 adds the event listener to the <ol> element and checks to see if the element clicked (e.target) is a delete button by checking the className attribute.
Related
I have a list and in each list group item there is a delete button. I would like the delete button to remove the list item. At the moment i can only delete the button but i would like the whole li element to be removed
function remove(ev) {
var elem = document.getElementById(ev.target.id);
elem.this.parentNode.id.remove();
console.log(elem.this.parentNode.id);
}
<ul class="list-group">
<li class="list-group-item">
<p>Item 1</p>
<button type="button" id="btn1" onclick="remove(event)" class="Button">Click</button>
</li>
<li class="list-group-item">
<p>Item 1</p>
<button type="button" id="btn1" onclick="remove(event)" class="Button">Click</button>
</li>
</ul>
You can use parentNode.remove()
function remove(ev) {
var elem = ev.target; // get the delete button element
elem.parentNode.remove(); // remove the parent li element
}
This may be a simple thing but I'm struggling on how to target an element on a click event. I got it working with jQuery but I want to do it in pure JavaScript. Basically I have this list:
<ul class= 'my-todo-list'>
<li id="todo-1" class="todo">
<div class="actions">
Edit
Delete
</div>
</li>
<li id="todo-2" class="todo">
<div class="actions">
Edit
Delete
</div>
</li>
<li id="todo-3" class="todo">
<div class="actions">
Edit
Delete
</div>
</li>
</ul>
and my JavaScript looks like this:
document.querySelector('.todo a.delete').addEventListener('click', function(e){
var listElement = this.parentNode.parentElement;
var todoId = listElement.getAttribute('id').replace('todo-','');
alert(todoId);
});
What I want is if I click on a delete link I should see the id for the todo. For example if I click on the second delete link I should alert "todo-2".
Note: I tried document.querySelector('.todo a.delete') but it didn't work either.
The easy solution with jQuery is
$('.todo a.delete').live('click', function(){......})
But I want to do it in pure JavaScript. How can I do that?
You can add an event listener on the ul element and check if the element that triggered the click event contains the delete class. If it does, get the id attribute from the li element wrapping that particular element which triggered the event
const $ul = document.querySelector('ul');
$ul.addEventListener('click', (e) => {
if (e.target.matches('a.delete')) {
const li = e.target.parentElement.parentElement;
const id = li.getAttribute('id');
alert(id);
}
});
<ul>
<li id="todo-1" class="todo">
<div class="actions">
Edit
Delete
</div>
</li>
<li id="todo-2" class="todo">
<div class="actions">
Edit
Delete
</div>
</li>
<li id="todo-3" class="todo">
<div class="actions">
Edit
Delete
</div>
</li>
</ul>
You can use querySelectorAll and map to map event as
[...document.querySelectorAll('.todo a.delete')].map((item) => {
item.addEventListener('click', function(e){
var listElement = this.parentNode.parentElement;
var todoId = listElement.getAttribute('id').replace('todo-','');
alert(todoId);
})
});
[...document.querySelectorAll('.todo a.delete')].map((item) => {
item.addEventListener('click', function(e){
var listElement = this.parentNode.parentElement;
var todoId = listElement.getAttribute('id').replace('todo-','');
alert(todoId);
})
});
<ul class= 'my-todo-list'>
<li id="todo-1" class="todo">
<div class="actions">
Edit
Delete
</div>
</li>
<li id="todo-2" class="todo">
<div class="actions">
Edit
Delete
</div>
</li>
<li id="todo-3" class="todo">
<div class="actions">
Edit
Delete
</div>
</li>
</ul>
Using the event target might not work sometimes when there is not a propagation.
Here is a script that I made and it works 100% with all browsers and easy to use too:
(It works even with dynamic elements just like jQuery)
// Advanced custom dynamic real time event handler listener supported 100% cross-browsers
String.prototype.addRTListener = function(events, renderingFunction){
let selectors = this.toString();
events = events.trim().split(' ');
for(let even of events){
even = even.trim();
if(even.length>0){
switch(even){
case "focus":
even = "focusin";
break;
case "blur":
even = "focusout";
break;
}
document.addEventListener(even, function(e){
const path = e.path;
document.querySelectorAll(selectors).forEach(function(element){
for(let target of path){
if( target == element ){
if( renderingFunction && typeof renderingFunction == "function" ){
renderingFunction(target, e);
}
break;
}
}
});
return;
});
}
}
}
<button id="testBtn">Click Me</button>
<script>
// We can add DOMContentLoaded eventListener just in case our script loads after the DOM other wise you could always load your script before and it should work just like a charm
document.addEventListener('DOMContentLoaded', ()=>{
// it supports multiple events too
"#testBtn".addRTListener('focus dblclick', (target, e)=>{
console.log( target );
});
});
</script>
I have 10-15 unordered lists in my HTML page, each containing a delete button next to each list item.
For each li to be uniquely identifiable, I have assigned to its id: its parent's id and its own category_name.
However, when I perform the remove() -- it doesn't work. The li does not get removed from its parent.
I already have an input box associated with each ul to add li's to the specific ul which is working.
<script>
function remove_category(ident){
$("#"+ident).remove;
}
function add_category(ul_id, input_id){
var ul = $("#"+ul_id);
var added_category = $("#"+input_id).val();
$(ul)
.append('<li class="list-group-item" id="'+added_category+'">'+added_category+'<button type="button" id="delete-category-btn" onclick="remove_category('+ul_id+added_category+');"><i class="fa fa-times delete-fa" aria-hidden="true"></i></button></li>')
}
</script>
The remove_category() function does not perform any action.
Probably because of the event handler is not taking dynamic element. Use .on to make the click event work on dynamic element
Here is the example.
$(document).on("click", ".added-category", function() {
var parent = $(this).closest("li");
parent.after("<li>" + parent.html() + "</li>");
});
$(document).on("click", ".remove-category", function() {
var parent = $(this).closest("li");
parent.remove();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>
some text
<button class="added-category">Add</button>
<button class="remove-category">Remove</button>
</li>
</ul>
Try to use this,
function removeLi(dhis){
dhis.parent().remove()
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li >list 1 <button onclick="removeLi($(this))">remove</button></li>
<li>list 2 <button onclick="removeLi($(this))">remove</button></li>
<li >list 3 <button onclick="removeLi($(this))">remove</button></li>
<li >list 4 <button onclick="removeLi($(this))">remove</button></li>
<li >list 5 <button onclick="removeLi($(this))">remove</button></li>
</ul>
So essentially I want to keep this as simple as possible, meaning no jquery or bootstrap etc... just straight javascript, HTML and CSS. This is what I have so far
Javscript:
var menuOptions= document.getElementsByClassName("nav");
var hamburger= document.getElementById("nav-btn");
function myFunction() {
hamburger.onclick= menuOptions.style.visibility= 'visible';
}
HTML:
<HTML>
<button onclick="myFunction()">
<span id="nav-btn">
<image src="Menugreen.png" alt="collapsable menu"/>
</span>
</button>
<div class="nav">
<ul>
<li id="Programs"> Programs </li>
<li> T-Shirts </li>
<li id="About"> About </li>
</ul>
</div>
</HTML>
CSS:
.nav {
visibility: hidden;
}
Besides just giving me a solution I would highly appreciate it if you could explain why my current method does not work and why yours does. Thanks in advance!
Two problems:
getElementsByClassName() returns a list, not a single element (though the list may contain just a single element), and that list doesn't have a .style property. You can use menuOptions[0] to access the first (and in this case only) element in the list.
You don't want to say hamburger.onclick= inside your function, because that would be assigning a new onclick handler but your function is already being called from the onclick attribute of your button. (Also, if you were trying to assign a new click handler you'd want hamburger.onclick = function() { /* something */ }.)
So the minimum change to your existing code to get it to work would be to change this line:
hamburger.onclick= menuOptions.style.visibility= 'visible';
...to this:
menuOptions[0].style.visibility = 'visible';
In context:
var menuOptions= document.getElementsByClassName("nav");
var hamburger= document.getElementById("nav-btn");
function myFunction() {
menuOptions[0].style.visibility = 'visible';
}
.nav {
visibility: hidden;
}
<HTML>
<button onclick="myFunction()">
<span id="nav-btn">
<image src="Menugreen.png" alt="collapsable menu"/>
</span>
</button>
<div class="nav">
<ul>
<li id="Programs"> Programs </li>
<li> T-Shirts </li>
<li id="About"> About </li>
</ul>
</div>
</HTML>
If you want repeated clicks on the button to toggle the menu display on and off then you can test the current visibility:
menuOptions[0].style.visibility =
menuOptions[0].style.visibility === 'visible' ? '' : 'visible';
Expand the following to see that working:
var menuOptions= document.getElementsByClassName("nav");
var hamburger= document.getElementById("nav-btn");
function myFunction() {
menuOptions[0].style.visibility =
menuOptions[0].style.visibility === 'visible' ? '' : 'visible';
}
.nav {
visibility: hidden;
}
<HTML>
<button onclick="myFunction()">
<span id="nav-btn">
<image src="Menugreen.png" alt="collapsable menu"/>
</span>
</button>
<div class="nav">
<ul>
<li id="Programs"> Programs </li>
<li> T-Shirts </li>
<li id="About"> About </li>
</ul>
</div>
</HTML>
There are a few reasons why your current setup does not function:
Document#getElementsByClassName returns a collection, and you are treating the result like a DOM element. You need to access an index like [0] to get an actual element.
Your toggle button only works one way, because visibility is set to visible but never set back to none when clicked again.
In myFunction, hamburger.onclick should not be assigned to the expression you chose. I am not sure why you tried to assign another click handler, but in order to make that work you would have needed to set it to a function () { ... }.
Now for my advice:
Use CSS classes to control whether the menu is hidden or not, rather than messing around with the style property in your JS. You can use the classList property of DOM elements to .add(), .remove(), and .toggle() a specific class when myFunction is run. I have chosen to use toggle because I think that most suits your use case.
Use element.addEventListener instead of HTML attributes like onclick.
Snippet:
var menuOptions = document.getElementsByClassName("nav")[0]
var hamburger = document.getElementById("nav-btn")
hamburger.parentNode.addEventListener('click', function myFunction() {
menuOptions.classList.toggle('hidden')
})
.nav.hidden {
visibility: hidden;
}
<button>
<span id="nav-btn">
<img src="Menugreen.png" alt="collapsable menu"/>
</span>
</button>
<div class="nav hidden">
<ul>
<li id="Programs"> Programs </li>
<li> T-Shirts </li>
<li id="About"> About </li>
</ul>
</div>
In HTML, I have a button list. If user clicks a button,
doCommand function will be called.
The code is following,
<ul>
<li class="button1" onclick="doCommand('bold');" id="bold-button" title="bold">B</li>
<li class="button2" onclick="doCommand('bold');" id="italic-button" title="bold">I</li>
<li class="button3" onclick="doCommand('bold');" id="underline-button" title="bold">U</li>
<li class="button4" onclick="doCommand('bold');" id="strikethrough-button" title="bold">S</li>
</ul>
This is plain expression, normal web programmer will code like that.
But, I want to hide onclick event and its function for security reason.
So the HTML code will be like this,
<ul>
<li class="button1" id="bold-button" title="bold">B</li>
<li class="button2" id="italic-button" title="bold">I</li>
<li class="button3" id="underline-button" title="bold">U</li>
<li class="button4" id="strikethrough-button" title="bold">S</li>
</ul>
Is there any efficient way to do this?
Hiding onclick property but do the same work.
I am using jQuery.
if you set the same class for the btns, you could easily do:
markup:
<ul>
<li class="button1 clickable" id="bold-button" title="bold">B</li>
<li class="button2 clickable" id="italic-button" title="bold">I</li>
<li class="button3 clickable" id="underline-button" title="bold">U</li>
<li class="button4 clickable" id="strikethrough-button" title="bold">S</li>
</ul>
js:
$('.clickable').click(function(){/* doCommand('bold') or whatever */})
Edit: if you want on click to directly transform the text to bold, you could use the this (that refers to the element you clicked, and you need to wrap it inside jQuery $) keyword inside the function i.e.
$('.clickable').click(function(){$(this).css('font-weight','bold')})
The class should be the same at all buttons, like this:
<li class="button button1"...
<li class="button button2"...
Then, you can do like this in javascript.
$("li.button").click(function() {
doCommand('bold');
});
Without changing your markup and using vanilla JS you can do it the following way.
const list = document.querySelector('ul');
list.addEventListener('click', e => {
if (e.target.classList.contains('button1')) {
console.log('bold');
};
if (e.target.classList.contains('button2')) {
console.log('italics');
};
if (e.target.classList.contains('button3')) {
console.log('underline');
};
if (e.target.classList.contains('button4')) {
console.log('strikethrough');
};
})
<ul>
<li class="button1" id="bold-button" title="bold">B</li>
<li class="button2" id="italic-button" title="bold">I</li>
<li class="button3" id="underline-button" title="bold">U</li>
<li class="button4" id="strikethrough-button" title="bold">S</li>
</ul>
I assign the event to the parent list, and check the class of the target allowing to do whatever action needed.
You can use jquery's document ready event to wire up the events:
$(function()
{
$("#bold-button").click(function(){doCommand('bold');});
}
);