I have a html dropdown menu. I want to select only the parent ul list items by jquery.
my menu code is:
<ul>
<li>list parent</li>
<li>list parent
<ul>
<li>list child</li>
<li>list child</li>
<li>list child</li>
<li>list child</li>
<li>list child</li>
</ul>
</li>
<li>list parent</li>
<li>list parent</li>
<li>list parent</li>
</ul>
I want to select only list parent to stylize. Not list child
You need to give your root ul a class or id here:
<ul id="rootUL">
Then you can use:
$('ul#rootUL > li').css(...);
The > selector helps you to select li elements which are the direct children of your list with id named rootUL
Add an identifier to the parent ul like an ID then use the child selector to select only its children
<ul id="nav">
<li>list parent</li>
<li>list parent
<ul>
<li>list child</li>
<li>list child</li>
<li>list child</li>
<li>list child</li>
<li>list child</li>
</ul>
</li>
<li>list parent</li>
<li>list parent</li>
<li>list parent</li>
</ul>
then
$('#nav > li')
The > selector allows you to select only the direct children of your elements.
So, assuming your root ul has a .root class set, you could use this :
$("ul.root > li")
Related
This is my code:
$(document).ready(function () {
$('<button class="btn more">View More</button>')
.appendTo(".listing-item-container")
.click(function() {
$(this).closest(".listing-item-container").removeClass("collapsed");
});
$('<button class="btn less">View Less</button>')
.appendTo(".listing-item-container")
.click(function() {
$(this).closest(".listing-item-container").addClass("collapsed");
});
});
.listing-item-container.collapsed > :nth-of-type(n+3) {
display:none;
}
.listing-item-container > .more {
display:none;
}
.listing-item-container > .less {
display:block;
}
.listing-item-container.collapsed > .more {
display:block;
}
.listing-item-container.collapsed > .less {
display:none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="listing-item-container collapsed">
<div class="listing-item">
<p>FEATURES</p>
<ul class="no-list-style">
<li>list content</li>
<li>list content</li>
<li>list content</li>
<li>list content</li>
</ul>
</div>
<div class="listing-item">
<p>FEATURES</p>
<ul class="no-list-style">
<li>list content</li>
<li>list content</li>
<li>list content</li>
<li>list content</li>
</ul>
</div>
<div class="listing-item">
<p>FEATURES</p>
<ul class="no-list-style">
<li>list content</li>
<li>list content</li>
<li>list content</li>
<li>list content</li>
</ul>
</div><div class="listing-item">
<p>FEATURES</p>
<ul class="no-list-style">
<li>list content</li>
<li>list content</li>
<li>list content</li>
<li>list content</li>
</ul>
</div>
<div class="listing-item">
<p>FEATURES</p>
<ul class="no-list-style">
<li>list content</li>
<li>list content</li>
<li>list content</li>
<li>list content</li>
</ul>
</div>
<!-- 100 more listing-item divs present here -->
</div>
In above code when I click view more, it will display all remaining 'listing item' div and when I click view less, all divs are collapsed and display only 2 divs.
My expected output is, when I click view more it should only display next 2 'listing item' div and view more button. Again If I click view more, it should display next 2 'listing item' div and view more button. This should continue for all 100 more 'listing item' div. In the end it should display view less button. When I click view less button, each time it should collapse last 2 'listing item' div.
How can I modify my code to get the expected output?
The key here is in the use of jquery slice() (same as javascript slice() but on a jquery collection).
var howManyItemsToShow = 2;
$(".listing-item").hide().slice(howManyItemsToShow).show();
this will hide all the items, then show the first 2. The UI update will be combined into a single action. If you add animation (.slideDown / .fadeIn) then this will need to be different.
You then add your "pagesize" (2 in the example) each time you click; and update.
Add a check for start/end and utilising the css trick to show/hide the more/less buttons gives you:
var lines = 2;
var pagesize = 2;
// assuming they don't change, load them up-front for small efficiency gain (and DRY)
var items = $(".listing-item-container .listing-item");
$(document).ready(function() {
$('<button class="btn more">View More</button>')
.appendTo(".listing-item-container")
.click(function() {
lines += pagesize;
items
.show()
.slice(lines).hide();
if (lines >= items.length)
$(this).closest(".listing-item-container").removeClass("collapsed");
});
$('<button class="btn less">View Less</button>')
.appendTo(".listing-item-container")
.click(function() {
// same for "less" but -= and different check
// this can of course be combined with the "more" button (DRY)
// shown separately for clarity
lines -= pagesize;
items.show();
items.slice(lines).hide();
if (lines <= pagesize)
$(this).closest(".listing-item-container").addClass("collapsed");
});
});
.listing-item-container.collapsed> :nth-of-type(n+3) {
display: none;
}
.listing-item-container>.more {
display: none;
}
.listing-item-container>.less {
display: block;
}
.listing-item-container.collapsed>.more {
display: block;
}
.listing-item-container.collapsed>.less {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="listing-item-container collapsed">
<div class="listing-item">
<p>FEATURES</p>
<ul class="no-list-style">
<li>list content</li>
<li>list content</li>
<li>list content</li>
<li>list content</li>
</ul>
</div>
<div class="listing-item">
<p>FEATURES</p>
<ul class="no-list-style">
<li>list content</li>
<li>list content</li>
<li>list content</li>
<li>list content</li>
</ul>
</div>
<div class="listing-item">
<p>FEATURES</p>
<ul class="no-list-style">
<li>list content</li>
<li>list content</li>
<li>list content</li>
<li>list content</li>
</ul>
</div>
<div class="listing-item">
<p>FEATURES</p>
<ul class="no-list-style">
<li>list content</li>
<li>list content</li>
<li>list content</li>
<li>list content</li>
</ul>
</div>
<div class="listing-item">
<p>FEATURES</p>
<ul class="no-list-style">
<li>list content</li>
<li>list content</li>
<li>list content</li>
<li>list content</li>
</ul>
</div>
<!-- 100 more listing-item divs present here -->
</div>
I will do that this way...
((parentRef='.listing-item-container', ItemsRef='.listing-item', startView=2, addView=2 )=>
{
const
listItems = document.querySelectorAll(ItemsRef)
, btMoreLess = document.querySelector(parentRef).appendChild( document.createElement('button'))
;
btMoreLess.className = 'showMore'
var listItemsViewCount = startView -addView;
btMoreLess.onclick =_=>
{
listItemsViewCount += btMoreLess.classList.contains('Less') ? -addView : +addView
listItems.forEach( (item,i)=> item.classList.toggle('noDisplay',i>=listItemsViewCount) )
if (listItemsViewCount >= listItems.length) btMoreLess.classList.add('Less')
else if (listItemsViewCount === startView) btMoreLess.classList.remove('Less')
}
btMoreLess.click() // init
}
)() // IIFE ending
.noDisplay{ display:none; }
button.showMore:before { content : 'View More'; }
button.showMore.Less:before { content : 'View Less'; }
.listing-item-container { counter-reset: itemCounter; }
.listing-item { counter-increment: itemCounter; }
.listing-item > p::before { content: counter(itemCounter) '.'; }
<div class="listing-item-container">
<div class="listing-item">
<p>FEATURES</p>
<ul> <li>list content</li> <li>list content</li> <li>list content</li> <li>list content</li> </ul>
</div>
<div class="listing-item">
<p>FEATURES</p>
<ul> <li>list content</li> <li>list content</li> <li>list content</li> <li>list content</li> </ul>
</div>
<div class="listing-item">
<p>FEATURES</p>
<ul> <li>list content</li> <li>list content</li> <li>list content</li> <li>list content</li> </ul>
</div>
<div class="listing-item">
<p>FEATURES</p>
<ul> <li>list content</li> <li>list content</li> <li>list content</li> <li>list content</li> </ul>
</div>
<div class="listing-item">
<p>FEATURES</p>
<ul> <li>list content</li> <li>list content</li> <li>list content</li> <li>list content</li> </ul>
</div>
<div class="listing-item">
<p>FEATURES</p>
<ul> <li>list content</li> <li>list content</li> <li>list content</li> <li>list content</li> </ul>
</div>
<div class="listing-item">
<p>FEATURES</p>
<ul> <li>list content</li> <li>list content</li> <li>list content</li> <li>list content</li> </ul>
</div>
<!-- 100 more listing-item divs present here -->
</div>
I am new to javascript, and I have encountered difficulties and hope to get your help!
My English is not good, but I try to describe my problem completely!
I hope the load() function can be triggered when the mouse scrolls to the bottom , How can the load() event be triggered when the mouse scrolls to the bottom?
Thank you for your help~
function show(){
let scrollposition = 0;
const el = document.querySelector('.demo');
el.addEventListener('scroll',function(e){
console.log('123');
load();
// let a = el.target.scrollTop;
// let b = el.target.innerHeight;
// let c = el.target.scrollHeight;
// if(currentscrollposition + windows >= total){
// console.log('bottom');
// }
})
}
show();
function load(){
let el = document.querySelector('.load');
el.style.display = 'block';
}
// // load()
.demo{
width: 200px;
height: 300px;
overflow-y:scroll;
background-color: #fff;
}
.item{
list-style:none;
padding:20px;
border:1px solid #ccc;
}
.load{
width:100%;
margin: 0 auto;
display: none;
}
<ul class="demo">
<li class="item">article1</li>
<li class="item">article2</li>
<li class="item">article3</li>
<li class="item">article4</li>
<li class="item">article5</li>
<li class="item">article6</li>
<li class="item">article7</li>
<li class="item">article8</li>
<li class="item">article9</li>
<li class="item">article10</li>
<!-- load -->
<svg class="load" version="1.1" id="loader-1" x="0px" y="0px"
width="40px" height="40px" viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
<path fill="#000" d="M43.935,25.145c0-10.318-8.364-18.683-18.683-18.683c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615c8.072,0,14.615,6.543,14.615,14.615H43.935z">
<animateTransform attributeType="xml"
attributeName="transform"
type="rotate"
from="0 25 25"
to="360 25 25"
dur="0.6s"
repeatCount="indefinite"/>
</path>
</svg>
</ul>
I hope it helps you:
var currPos = window.scrollY;
document.addEventListener('scroll', () => {
if (window.scrollY < currPos) {
//scroll up
console.log('Scroll Up');
} else {
//scroll down
console.log('Scroll Down');
}
currPos = window.scrollY;
});
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<header>Header</header>
<main>
<ol>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
<li>List Element</li>
</ol>
</main>
<footer>Footer</footer>
</body>
</html>
If you want to call a function when scroll get the bottom of the list you should get the position of the last child and scroll position and when scroll reach the last child then call the function.
function show() {
let scrollposition = 0;
const ul = document.querySelector('.demo');
ul.addEventListener('scroll', function(e) {
var li = ul.children[ul.children.length - 2];
if (ul.scrollTop + ul.offsetHeight > li.offsetTop) {
document.getElementById('loading').innerHTML = "loading...";
load();
}
else{
document.getElementById('loading').innerHTML = "";
}
})
}
show();
function load() {
let el = document.querySelector('.load');
el.style.display = 'block';
}
// // load()
#loading {
width: 100px;
float: right;
}
.demo {
width: 200px;
height: 300px;
overflow-y: scroll;
background-color: #fff;
}
.item {
list-style: none;
padding: 20px;
border: 1px solid #ccc;
}
.load {
width: 100%;
margin: 0 auto;
display: none;
}
<div id="loading">
</div>
<ul id="demo" class="demo">
<li class="item">article1</li>
<li class="item">article2</li>
<li class="item">article3</li>
<li class="item">article4</li>
<li class="item">article5</li>
<li class="item">article6</li>
<li class="item">article7</li>
<li class="item">article8</li>
<li class="item">article9</li>
<li class="item">article10</li>
<!-- load -->
<svg class="load" version="1.1" id="loader-1" x="0px" y="0px" width="40px" height="40px" viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
<path fill="#000" d="M43.935,25.145c0-10.318-8.364-18.683-18.683-18.683c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615c8.072,0,14.615,6.543,14.615,14.615H43.935z">
<animateTransform attributeType="xml"
attributeName="transform"
type="rotate"
from="0 25 25"
to="360 25 25"
dur="0.6s"
repeatCount="indefinite"/>
</path>
</svg>
</ul>
I have bare basic knowledge in JavaScript, and I'm trying to create a menu where :
Only the first level parents are visible.
Then when you click on them, their children will be displayed.
If you click on them again (or maybe click anywhere on the page) they will close
Must work for 2 level children (for example children of children)
This is what I have so far, and I know this is far from being right. I found a bunch of jQuery solutions online, but I want it pure JavaScript & CSS.
Note: I also need to keep the number of classes & id's used to a minimum as I want to be able to use this with the WordPress menu structure. But if I need to manually add a "parent" class to each parent that has children, then that will be fine.
My JavaScript :
var menuParents = document.querySelectorAll("#my-menu .parent");
menuParents.forEach(menuParent => {
document.querySelector("#my-menu .parent").addEventListener("click", ToggleMenu);
function ToggleMenu() {
document.querySelector("#my-menu .parent ul").style.display = 'block';
}
});
My CSS :
#my-menu .parent ul {display: none;}
And, finally, my HTML :
<ul id="my-menu">
<li>Standard Item</li>
<li>Standard Item</li>
<li class="parent">Item with children
<ul>
<li>child item</li>
<li>child item</li>
<li class="parent">child item with children
<li>second level child</li>
<li>second level child</li>
</li>
<li>child item</li>
<li>child item</li>
</ul>
</li>
<li>Standard Item</li>
<li>Standard Item</li>
<li class="parent">Item with children
<ul>
<li>child item</li>
<li>child item</li>
<li class="parent">child item with children
<li>second level child</li>
<li>second level child</li>
</li>
<li>child item</li>
<li>child item</li>
</ul>
</li>
<li>Standard Item</li>
<li>Standard Item</li>
</ul>
You need to use the specific element in the forEach, and then just get the firstElementChild of it, and toggle the display style:
const toggle = {
block: 'none',
none: 'block'
}
function ToggleMenu(event) {
event.stopPropagation();
event.target.classList.toggle('active');
event.target.firstElementChild.style.display = toggle[event.target.firstElementChild.style.display] || 'block';
}
var menuParents = document.querySelectorAll("#my-menu .parent");
menuParents.forEach(menuParent => {
menuParent.addEventListener("click", ToggleMenu);
})
#my-menu .parent ul {display: none;}
.active {
color: red
}
.active > * {
color: black
}
<ul id="my-menu">
<li>Standard Item</li>
<li>Standard Item</li>
<li class="parent">Item with children
<ul>
<li>child item</li>
<li>child item</li>
<li class="parent">child item with children
<ul>
<li>second level child</li>
<li>second level child</li>
</ul>
</li>
<li>child item</li>
<li>child item</li>
</ul>
</li>
<li>Standard Item</li>
<li>Standard Item</li>
<li class="parent">Item with children
<ul>
<li>child item</li>
<li>child item</li>
<li class="parent">child item with children
<ul>
<li>second level child</li>
<li>second level child</li>
</ul>
</li>
<li>child item</li>
<li>child item</li>
</ul>
</li>
<li>Standard Item</li>
<li>Standard Item</li>
</ul>
or without "parent" class
const toggle = {
block: 'none',
none: 'block'
}
function ToggleMenu(event) {
event.stopPropagation();
if (event.target.firstElementChild) {
event.target.classList.toggle('active');
event.target.firstElementChild.style.display = toggle[event.target.firstElementChild.style.display] || 'block';
}
}
var menuParents = document.querySelectorAll("#my-menu li > ul");
menuParents.forEach(menuParent => {
menuParent.parentElement.addEventListener("click", ToggleMenu);
})
#my-menu li > ul {display: none;}
.active {
color: red
}
.active > * {
color: black
}
<ul id="my-menu">
<li>Standard Item</li>
<li>Standard Item</li>
<li>Item with children
<ul>
<li>child item</li>
<li>child item</li>
<li>child item with children
<ul>
<li>second level child</li>
<li>second level child</li>
</ul>
</li>
<li>child item</li>
<li>child item</li>
</ul>
</li>
<li>Standard Item</li>
<li>Standard Item</li>
<li>Item with children
<ul>
<li>child item</li>
<li>child item</li>
<li>child item with children
<ul>
<li>second level child</li>
<li>second level child</li>
</ul>
</li>
<li>child item</li>
<li>child item</li>
</ul>
</li>
<li>Standard Item</li>
<li>Standard Item</li>
</ul>
Your HTML is slightly wrong: your parents inside parents don't have ul elements.
<ul id="my-menu">
<li>Standard Item</li>
<li>Standard Item</li>
<li class="parent">Item with children
<ul>
<li>child item</li>
<li>child item</li>
<li class="parent">child item with children
<!-- here -->
<ul>
<li>second level child</li>
<li>second level child</li>
</ul>
</li>
</ul>
</li>
<li>child item</li>
<li>child item</li>
<li>Standard Item</li>
<li>Standard Item</li>
<li class="parent">Item with children
<ul>
<li>child item</li>
<li>child item</li>
<li class="parent">child item with children
<!-- and here -->
<ul>
<li>second level child</li>
<li>second level child</li>
</ul>
</li>
</ul>
</li>
<li>child item</li>
<li>child item</li>
<li>Standard Item</li>
<li>Standard Item</li>
</ul>
JavaScript wise, your toggle function doesn't actually toggle anything, or it won't toggle more than once, anyway.
Another problem is that the click handler will also get called when you click on a parent of a parent, which this code accounts for too.
Here I used an anonymous function. You don't have to do this, a named function would work just fine, but it doesn't clutter your only namespace.
This will also work with any level of parents: the attached snippet has second level parents.
var menuParents = document.querySelectorAll("#my-menu .parent");
menuParents.forEach(
menuParent => {
menuParent.addEventListener(
"click",
// inline, anonymous function
// also accepts an event parameter
function (event) {
// check if the parent element was actually clicked (prevent parent of parent from toggling display)
if (event.target == this) {
// this == menuParent
// select ul from menuParent
var menuChild = this.querySelector("ul");
// toggle child menu display, based on it's current display
if (menuChild.style.display == "block") {
// here, you could also set the display to null, since your CSS sets the display to none anyway
menuChild.style.display = "none";
} else {
menuChild.style.display = "block";
}
}
}
);
}
);
Tested on Chrome 87.0.4280.88.
var menuParents = document.querySelectorAll("#my-menu .parent");
menuParents.forEach(
menuParent => {
menuParent.addEventListener(
"click",
// inline, anonymous function
// also accepts an event parameter
function (event) {
if (event.target == this) {
// this == menuParent
// select ul from menuParent
var menuChild = this.querySelector("ul");
// toggle child menu display, based on it's current display
if (menuChild.style.display == "block") {
// here, you could also set the display to null, since your CSS sets the display to none anyway
menuChild.style.display = "none";
} else {
menuChild.style.display = "block";
}
}
}
);
}
);
#my-menu .parent ul {
padding-left: 16px;
display: none;
}
<ul id="my-menu">
<li>Standard Item</li>
<li>Standard Item</li>
<li class="parent">Item with children
<ul>
<li>child item</li>
<li>child item</li>
<li class="parent">child item with children
<ul>
<li>second level child</li>
<li>second level child</li>
<li class="parent">second level parent
<ul>
<li>third level child</li>
<li>third level child</li>
</ul>
<li>second level child</li>
<li>second level child</li>
</ul>
</li>
<li>child item</li>
<li>child item</li>
</ul>
</li>
</li>
<li>Standard Item</li>
<li>Standard Item</li>
<li class="parent">Item with children
<ul>
<li>child item</li>
<li>child item</li>
<li class="parent">child item with children
<ul>
<li>second level child</li>
<li>second level child</li>
<li class="parent">second level parent
<ul>
<li>third level child</li>
<li>third level child</li>
</ul>
</li>
<li>second level child</li>
<li>second level child</li>
</ul>
</li>
<li>child item</li>
<li>child item</li>
</ul>
</li>
<li>Standard Item</li>
<li>Standard Item</li>
</ul>
I have a list of filter checkboxes that are written in via JavaScript. The filter checkboxes come from divs with values that could be repeated.
<div value="a" class="foo">
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
</div>
<div value="b" class="foo">
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
</div>
<div value="c" class="foo">
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
</div>
<div value="c" class="foo">
<li>list item</li>
<li>list item</li>
</div>
I have an array of those different div values. (I cut to the chase here and am just showing the result of the array rather than how I created it.)
var allDivs = ["a", "b", "c", "c", "d", "e", "e", "f"]
I have a filtered version of the array so there are no duplicates. I use this array to generate a set of filter checkboxes.
var filteredDivs = ["a", "b", "c", "d", "e", "f"]
What I'd like to do:
Each div contains a number of list items within it.
Next to each filter checkbox (from the filtered array with no duplicates), I'd like to provide a count of the li elements, combining the number of li elements from the duplicated entries.
So here's a representation of the number of li elements in each div.
a = 4
b = 5
c = 2
c = 7
d = 5
e = 2
e = 3
f = 6
...but combined (because I have two 'c' and 'e' divs), that would be:
a = 5
b = 5
c = 9
d = 5
e = 5
f = 6
I am able to get those individual counts by doing something like
$("a li").length
$("b li").length
$("c li").length
but I am having trouble turning that into a function.
For a bit more context...the filter checkboxes are written in like this, just to give you an idea.
var renderFilters = function (filteredDivs) {
app.querySelector("#filters").innerHTML =
filteredDivs.map(function (module, index) {
var html =
'<label class="filter">' +
'<input type="checkbox" data-filter="' + filteredDivs[index] + '" checked>' +
module + " (" + ")" // Would like the count of li items here.
'</label>';
return html;
}).join('')
};
In addition to writing in the list of unique div values as filter checkboxes, I'd also like to display the count of the li items in the parentheses, combining them where appropriate.
I don't know where to start on this problem. I'm hoping someone can point me in the right direction so that I can research an answer, if there is one.
You could do it like this:
var divs = document.querySelectorAll('[value]')
var values = Array.from(divs).map(d => d.getAttribute('value'));
var unique_values = Array.from(new Set(values));
var counts = unique_values.map(c => ({value: c, count: document.querySelectorAll('[value="' + c + '"] li').length}))
console.log(counts);
<div value="a" class="foo">
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
</div>
<div value="b" class="foo">
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
</div>
<div value="c" class="foo">
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
</div>
<div value="c" class="foo">
<li>list item</li>
<li>list item</li>
</div>
I have this code. When I click on any li element then the first alert it shows its value, then show its parent then again that parent and so on. I just want to show the text of the clicked li element. How can I do that?
$('#container li').on('click', function() {
alert($(this).text());
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<ul class="xyz">
<li>Grand Parent 1</li>
<li>
<ul class="xyz">
<li>Parent 1</li>
<li>Parent 2
<ul class="xyz">
<li>Child 1</li>
<li>Child 2</li>
<li>Child 3</li>
<li>Child 4</li>
</ul>
</li>
<li>Parent 3</li>
<li>Parent 4</li>
</ul>
</li>
</ul>
</div>
Your first issue is that you need to stop the proprgation of the event from the clicked li to the parent li elements. You can call stopPropagation on the passed event handler to do that.
Secondly, I assume you only want to retrieve the child text value of the li, not the text of it's descendants, in which case you would need to use contents()[0] to access it. Try this:
$('#container li').on('click', function(e) {
e.stopPropagation();
var text = $(this).contents()[0].nodeValue.trim();
console.log(text);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<ul class="xyz">
<li>Grand Parent 1</li>
<li>
<ul class="xyz">
<li>Parent 1</li>
<li>
Parent 2
<ul class="xyz">
<li>Child 1</li>
<li>Child 2</li>
<li>Child 3</li>
<li>Child 4</li>
</ul>
</li>
<li>Parent 3</li>
<li>Parent 4</li>
</ul>
</li>
</ul>
</div>