I have this code that will console.log the innerHTML of the list element that is clicked, it works perfectly
But I wanted to only console.log the innerHTML of the span element with class "x" that is inside the list
how can I do this?
function myfunction() {
let items = document.querySelectorAll("#ol li"),
array = [];
for (var i = 0; i < items.length; i++) {
array.push(items[i].innerHTML);
}
for (var i = 0; i < items.length; i++) {
items[i].onclick = function() {
console.log(this.innerHTML)
}
};
}
<ol id="ol">
<li>
<span class="x">hello</span>
<span class="xx">testing</span>
</li>
<li>
<span class="x">hello2</span>
<span class="xx">testing2</span>
</li>
<li>
<span class="x">hello3</span>
<span class="xx">testing4</span>
</li>
<li>
<span class="x">hello4</span>
<span class="xx">testing4</span>
</li>
</ol>
<button onclick="myfunction()">click</button>
Rather than placing a listener on each li, you can take advantage of event delegation, placing a single handler on the ol:
<ol id="ol">
<li>
<span class="x">hello</span>
<span class="xx">testing</span>
</li>
<li>
<span class="x">hello2</span>
<span class="xx">testing2</span>
</li>
<li>
<span class="x">hello3</span>
<span class="xx">testing4</span>
</li>
<li>
<span class="x">hello4</span>
<span class="xx">testing4</span>
</li>
</ol>
<button id="button">click</button>
'use strict';
const button = document.querySelector('#button');
const findLI = el => {
if (el.tagName.toLowerCase() === 'li') {
return el;
}
return findLI(el.parentElement);
};
const registerItemsClickHandler = () => {
const ol = document.querySelector('#ol');
ol.onclick = event => {
const li = findLI(event.target);
console.log(li.innerHTML);
};
};
button.onclick = registerItemsClickHandler;
Notice that we only register a single click handler (on the ol) and that we can use event.target to determine the specific element onto which the event was dispatched. It's also worth noting that a child any depth of the tree can be a dispatch target, so we can use the recursive findLI() function to find the first parent that is an li, if el itself isn't one.
Related
I am using two navbars. Both of them share a single class ('navbar-item'). Basically both navbars do the same things.
E.g.
navbar-1
<a class="navbar-item" href="#Services">
<span class="icon"><i class="fas fa-clipboard-list"></i></span>
<span>Services</span>
</a>
<a class="navbar-item" href="#Delivery">
<span class="icon"><i class="fas fa-shipping-fast"></i></span>
<span>Delivery</span>
</a>
<a class="navbar-item" href="#Contact">
<span class="icon"><i class="fas fa-shipping-fast"></i></span>
<span>Contact</span>
</a>
navbar-2
<li class="navbar-item"></li>
<li class="navbar-item"></li>
<li class="navbar-item"></li>
I am looking to add/remove another class name ('current') when clicked. I want to add this new class name ('current') to both navbars. So when "Services" is clicked, in both navbrs only the "Services" should have the class current. When "Delivery" is clicked, in both navbrs only the "Delivery" should have the class current.
I am looking for a pure js solution (no jQuery). This is what I have so far.
This passes the new class name (current) only to the first navbar.
var btns = document.getElementsByClassName("navbar-item");
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", function() {
var current = document.getElementsByClassName("current");
current[0].className = current[0].className.replace(" current", "");
this.className += " current";
});
}
Note:- this is the way you can detect selected div using that you can toggle(add/remove) class based on the selected element.
var div1 = document.getElementById("First");
div1.addEventListener("click", function (e) {
if (event.currentTarget.classList.contains('active')) {
event.currentTarget.classList.remove('active');
var element = document.getElementById("Second");
element.classList.add("active");
} else {
event.currentTarget.classList.add('active');
var element = document.getElementById("Second");
element.classList.remove("active");
}
});
var div2 = document.getElementById("Second");
div2.addEventListener("click", function (e) {
if (event.currentTarget.classList.contains('active')) {
event.currentTarget.classList.remove('active');
var element = document.getElementById("First");
element.classList.add("active");
} else {
event.currentTarget.classList.add('active');
var element = document.getElementById("First");
element.classList.remove("active");
}
});
.active{
color:red;
}
<div id"newNav">
<a class="navbar-item te" id="First" href="#Delivery">
<span class="icon"><i class="fas fa-shipping-fast"></i></span>
<span>Delivery</span>
</a>
<li class="navbar-item" id="Second">
<span>Delivery2</span>
</li>
</div>
Use document.querySelectorAll()
The Document method querySelectorAll() returns a static (not live)
NodeList representing a list of the document's elements that match the
specified group of selectors.
document.querySelectorAll('nav.navbar-item')
.forEach((node) => node.className += ' current')
Here, nav.navbar-item is the selection required, and current is the new class to be appended to the nodes selected by querySelector.
Adding verbose solution:
let classToBeAdded = 'current';//new class to be added
let myNavs = document.querySelectorAll('nav.navbar-item');//Selects all navs with the given class
for(let element of myNavs) {//looping through the elements captured by the above query
element.classList.add(classToBeAdded);//Appending new class to the element
}
I'm trying to create a list of input tags along with delete button next to it. When I click on delete button, the input tag next to it should also get deleted. Here only the button gets deleted but not the respective li. How do I go about this?
var buttonItems = document.querySelectorAll(".deleteButton");
var listItems = document.getElementsByTagName("li");
for (var i = 0; i < buttonItems.length; i++) {
for (var i = 0; i < listItems.length; i++) {
buttonItems[i].addEventListener('click',function(e){
this.remove(this)
listItems[this].remove()
})
}
}
You get parentNode, which Element inherits from Node:
In ES5
document.querySelectorAll(".deleteButton").forEach(function(btn) {
//Add listener for click event on delete button
btn.addEventListener('click', function(e) {
//it will always return the li tag
//beucase lit tag is parent of button..
e.target.parentNode.remove();
});
});
<ul>
<li>Coffee<button class="deleteButton">Delete</button></li>
<li>Tea <button class="deleteButton">Delete</button></li>
<li>Milk <button class="deleteButton">Delete</button></li>
</ul>
In ES6
document.querySelectorAll(".deleteButton").forEach(btn => {
//Add listener for click event on delete button
btn.addEventListener('click', e => e.target.parentNode.remove());
});
<ul>
<li>Coffee<button class="deleteButton">Delete</button></li>
<li>Tea <button class="deleteButton">Delete</button></li>
<li>Milk <button class="deleteButton">Delete</button></li>
</ul>
References:
DOM2 Core specification - well-supported by all major browsers
DOM2 HTML specification - bindings between the DOM and HTML
DOM3 Core specification - some updates, not all supported by all major browsers
HTML5 specification - which now has the DOM/HTML bindings in it
Use items parent to .removeChild.
var deleteButtons = document.querySelectorAll(".delete-button");
var grandparent;
for (var i = 0; i < deleteButtons.length; i++) {
deleteButtons[i].addEventListener('click',function(e){
grandparent = e.target.parentElement.parentElement;
grandparent.removeChild(e.target.parentElement);
});
}
<ul>
<li>
Test Test 1<button class="delete-button">Delete</button>
</li>
<li>
Test Test 2<button class="delete-button">Delete</button>
</li>
<li>
Test Test 3<button class="delete-button">Delete</button>
</li>
<li>
Test Test 4<button class="delete-button">Delete</button>
</li>
<li>
Test Test 5<button class="delete-button">Delete</button>
</li>
</ul>
I have my ul : li list with a span named as badge which contains the total number of unread messages. So i want to shuffle all the li items with the highest number on top of the list and lowest or none to the last. I tried many solutions but still can`t get it. Another point is the count gets update live so the list should also shuffle live. Here is the code that i tried till now.
My HTML Code
<li>
<span class="badge" style="display:none" id="61_T">0</span>
</li>
<li>
<span class="badge" style="display:none" id="62_T">5</span>
</li>
<li>
<span class="badge" style="display:none" id="63_T">10</span>
</li>
<li>
<span class="badge" style="display:none" id="64_T">0</span>
</li>
Here is my JS Code
var prev_index = 0;
var curr_index = 0;
var curr_val = 0;
var prev_val = 0;
var lists = $('#items li');
var msg_count = [];
$('#items li').each(function(){
var current_index = $(this).index();
var count = $(this).find('.badge').text();
msg_count.push([current_index,count]);
});
updateli();
function updateli(){
$.each(msg_count,function(key,value){
var str = value.join('-');
var sep = str.split('-');
curr_index = sep[0];
curr_val = parseInt(sep[1]);
if(curr_val > prev_val){
$("#items li:eq("+curr_index+")").siblings().eq(curr_index).after(lists.siblings(':eq('+prev_index+')'));
}
prev_index = curr_index;
prev_val = curr_val;
});
}
What i did here is created an array with li index and unread count number. After than looped the array and used jQuery function to swap the elements but nothing seems to work. Any help will really appreciated. Thanks in advance.
This sorts the list without using JQuery
function sortItems(containerSelector, itemSelector, countSelector, asc) {
let container = document.querySelector(containerSelector);
let items = [].slice.call(container.querySelectorAll(itemSelector));
items.sort(function(currItem, nextItem) {
var currCountElement = currItem.querySelector(countSelector);
var nextCountElement = nextItem.querySelector(countSelector);
if(!currCountElement) return 1;
if(!nextCountElement) return -1;
var currCount = parseInt(currCountElement.textContent || -1);
var nextCount = parseInt(nextCountElement.textContent || -1);
var order = currCount - nextCount;
return asc?-order:order;
});
items.forEach(function(item) { container.appendChild(item)});
}
// demo code
[].slice.call(document.querySelectorAll('.sortButton')).forEach(function(button) {
button.addEventListener('click', function(e) { sortItems('.items', 'li', '.badge', this.classList.contains('-desc')) });
});
<ul class="items">
<li>
2
<span class="badge" style="display:none" id="61_T">2</span>
</li>
<li>
5
<span class="badge" style="display:none" id="62_T">5</span>
</li>
<li>
10
<span class="badge" style="display:none" id="63_T">10</span>
</li>
<li>
1
<span class="badge" style="display:none" id="63_T">1</span>
</li>
<li>
0
<span class="badge" style="display:none" id="64_T">0</span>
</li>
<li>
none
<span class="badge" style="display:none" id="64_T"></span>
</li>
<li>
no badge
</li>
</ul>
<button class="sortButton">asc</button>
<button class="sortButton -desc">desc</button>
Edit: made it a method
try the code below please.jquery return a array-like object so you can sort elements by sort(..) method,and then replace all the li.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>
<span class="badge" id="61_T">0</span>
</li>
<li>
<span class="badge" id="62_T">5</span>
</li>
<li>
<span class="badge" id="63_T">10</span>
</li>
<li>
<span class="badge" id="64_T">0</span>
</li>
</ul>
<script>
var badges = $('.badge').parent().sort(function (a, b) {
return parseInt($(b).find('span').text()) - parseInt($(a).find('span').text());
});
badges.closest('ul').empty().append(badges);
</script>
I have a component which have buttons and list both of which perform events on click. I need a common way to get the ancestor element for these elements. The structure looks like
<div class='a'>
<button class ='b' data-name="hello">
<span class ='c'>clickMe
<span>somehting</span>
</span>
<button>
<ul class ='d'>
<li data-name="about">
<span class ='e'>something here
<span>somehting</span>
</span>
</li>
<li data-name="home">
<span class ='e'>something elser here
<span>somehting</span>
</span>
</li>
</ul>
</div>
I try to get the element button and li because I need to get data-name information.
e.target is the element that was clicked
var targetel = goog.dom.getAncestorByClass(e.target,null,class??);
Not sure how to get the correct element irrespective if its a button or li. Do i need to add a unique class to all the elements ?
Just use e.currentTarget
var result = document.querySelector('#result');
var clickables = document.querySelectorAll('button, li');
//add click listener to elements
for (var i = 0, l = clickables.length; i < l; i++) {
clickables[i].addEventListener('click', getDataName);
}
function getDataName(e) {
var dataName = e.currentTarget.getAttribute('data-name');
result.textContent = dataName;
}
<div class='a'>
<button class ='b' data-name="hello">
<span class ='c'>clickMe
<span>somehting</span>
</span>
</button>
<ul class ='d'>
<li data-name="about">
<span class ='e'>something here
<span>somehting</span>
</span>
</li>
<li data-name="home">
<span class ='e'>something elser here
<span>somehting</span>
</span>
</li>
</ul>
</div>
<div id="result">data-name of clicked element goes here</div>
https://api.jquery.com/parents/
Use the jquery.parents("li") function. it will select all the parents that match your css filter. so you can do
var parentli = targete1.parents("li");
var button = targete1.parents("div").children[0];
Or something similar to that.
EDIT:
Not sure why i got downvoted, here is my idea in action.
maybe press f12 to inspect element and look at the console log.
var onClick = function () {
var parentEl = $(this).parents("button, li")[0];
console.log(parentEl);
$("#result")[0].innerText = parentEl.getAttribute("data-name");
};
$('span.c').click(onClick);
$('li span.e').click(onClick);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='a'>
<button class='b' data-name="hello">
<span class='c'>clickMe
<span>something</span>
</span>
</button>
<ul class ='d'>
<li data-name="about">
<span class ='e'>something here
<span>somehting</span>
</span>
</li>
<li data-name="home">
<span class ='e'>something elser here
<span>something</span>
</span>
</li>
</ul>
</div>
<div id="result">result goes here</div>
I have a ul consisting of several li's in it. Now I wanted to add Edit And Delete option infront of every li so that it can be Edited or Deleted on click.
How can i do this ?
Thanks in Advance for any help :)
See this DEMO
$('ul li').each(function () {
$(this).append('<a class="delete" href="#">Delete</a> Edit')
});
$('ul li a.delete').on('click', function () {
$(this).parent().remove();
return false;
});
$('ul li a.edit').on('click', function () {
var val = $(this).siblings('span').html();
if (val) {
$(this).parent().prepend('<input type="text" class="txt" value="' + val + '" />');
$(this).siblings('span').remove();
$(this).html('Update');
} else {
var $txt = $(this).siblings().filter(function() { return $(this).hasClass('txt') });
$(this).parent().prepend('<span class="lead justified">' + $txt.val() + '</span>');
$txt.remove();
$(this).html('Edit');
}
return false;
});
I strongly suggest you use Jquery or another library to handle cross browser issues. Anyway, here is the solution with pure javascript... it should work in all modern browsers recent versions.
SOLUTION DEMO
HTML
<ul class="fa-ul">
<li>
<span> BE/ BTech/ MCS </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Solid </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Strong </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Sharp </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Ability</span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Deal problems</span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Strong </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Excellent </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
</ul>
JS
var removeClassElements = document.getElementsByClassName('remove');
for(var i = 0; i < removeClassElements.length; i++){
var element = removeClassElements[i];
element.addEventListener('click', remove);
}
var editClassElements = document.getElementsByClassName('edit');
for(var i = 0; i < editClassElements.length; i++){
var element = editClassElements[i];
element.addEventListener('click', edit);
}
function remove() {
var li = this.parentNode;
var ul = li.parentNode;
ul.removeChild(li);
}
function edit() {
var li = this.parentNode;
var span = li.children[0];
span.setAttribute('contenteditable', true);
span.focus();
}
PS: You don't need class="lead justified" in each li element. You can use a CSS rule like this:
.fa-ul li span:first-child {...}
You can use CSS trick to perform inplace edit on span's and jQuery#remove() for deleting li's.
Idea is to hide the text when Edit is clicked and show textbox and vice-versa on click of Delete.
$('button.edit').click(function(){
var label_element = $(this).parent().find('span'),
input_element = $(this).parent().find('input');
label_element.addClass('editing');
input_element.val(label_element.text());
input_element.addClass('editing');
});
$('button.delete').click(function(){
$(this).parent().remove();
});
$('input').blur(function(){
var label_element = $(this).parent().find('span');
label_element.text($(this).val());
$(this).removeClass('editing');
label_element.removeClass('editing');
});
Fiddle DEMO
<ul class="fa-ul">
<li><span class="lead justified"> BE/ BTech/ MCS </span>DeleteEdit</li>...
The function edit(this) is given incorrectly and this links to <a>Edit</a>.
You should add id property to the <span>.
<li><span class="lead justified" id="foo"> BE/ BTech/ MCS </span>DeleteEdit</li>
<script>
function edit(target) {
target.contenteditable = true;
}
</script>
You need do change some changes in your markups, You can take <div> instead of <span> and can apply HTML5's attribute contenteditable
Sample Markup
<li>
<div class="lead justified">BE/ BTech/ MCS</div>
Delete
Edit
</li>
Script
Edit
function edit(elem){
$(elem).siblings('div.lead').attr('contenteditable',true);
}
Delete
function remove(elem){
$(elem).closest('li').remove(); // Deletes li
return false;
}
Fiddle Demo