nested li value on click not working - javascript

I have elements which have nested li elements and i made a click function to get the value. Every time i click i am getting the same value again and again.
<script type="text/javascript">
$('.cat-select').on('click',function(){
$('.cat-list').css('display','block');
$('.sub-list').css('display','block');
});
$(document).on('click','.cat-list>li',function(){
var selectedVal = $(this).clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.text(); //get the text of elemen
console.log(selectedVal);
$('.cat-select').text(selectedVal);
});
</script>
<div class="form-group">
<label for="input-placeholder" class="col-sm-2 control-label"></label>
<div class="col-sm-10">
<style type="text/css">
.cat-list, .sub-list{ display: none; }
</style>
<div class="cat-group">
<button class="cat-select" type="button">Select Category</button>
<ul class="cat-list">
<li class="have-child">Electronics
<ul class="sub-list">
<li class="have-child"> Mobiles & Tablets
<ul class="sub-list">
<li>Mobiles</li>
<li>Tablets</li>
<li class="have-child">Accessories</li>
<ul>
<li>Power Bank</li>
<li>Phone Cases</li>
</ul>
</ul>
</li>
<li class="have-child">Cameras
<ul class="sub-list">
<li>DSLRs</li>
<li>Drones</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
Every time i click i am getting the same value
https://jsfiddle.net/yx4Ldt80/

The issue you see is because you only attach the event handler to the child of the .cat-list through your use of the > operator.
To solve this, remove that from the selector and call stopPropagation() on the event to stop it bubbling up the DOM. Try this:
$(document).on('click', '.cat-list li', function(e) {
e.stopPropagation();
var selectedVal = $(this).clone().children().remove().end().text();
$('.cat-select').text(selectedVal);
})
$('.cat-select').on('click', function() {
$('.cat-list, .sub-list').toggle();
});
$(document).on('click', '.cat-list li', function(e) {
e.stopPropagation();
var selectedVal = $(this).clone().children().remove().end().text();
$('.cat-select').text(selectedVal);
})
.cat-list,
.sub-list {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="form-group">
<label for="input-placeholder" class="col-sm-2 control-label"></label>
<div class="col-sm-10">
<div class="cat-group">
<button class="cat-select" type="button">Select Category</button>
<ul class="cat-list">
<li class="have-child">Electronics
<ul class="sub-list">
<li class="have-child">
Mobiles & Tablets
<ul class="sub-list">
<li>Mobiles</li>
<li>Tablets</li>
<li class="have-child">Accessories
<ul>
<li>Power Bank</li>
<li>Phone Cases</li>
</ul>
</li>
</ul>
</li>
<li class="have-child">
Cameras
<ul class="sub-list">
<li>DSLRs</li>
<li>Drones</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
Also note that I fixed the HTML in your 'Accessories' ul as it was outside of the parent li.

"Never use" Event.stopPropagation()
The worst thing you can do (as suggested by answers here and around the web) is to use Event.stopPropagation().
Don't use Event.stopPropagation(), well, unless you really know what you're doing.
An Application should be always aware of every event happening in it's context.
Imagine you build a popup, modal, or a custom select-box that needs to close if you click anywhere else in the page. Well, congratulations, a LI element just stopped you from doing so.
Use Event.target instead
function myClickHandler(ev) {
if (ev.target !== this) return; // Ignore if non-this called the event
console.log( this.textContent );
}
Here's an example with your specific use-case:
const $cat = $('.cat-select');
$cat.on('click', function() {
$('.cat-list, .sub-list').toggle();
});
$(document).on('click', '.cat-list li', function(ev) {
if (ev.target !== this) return; // Ignore if non-this called the event
const value = $(this).contents().filter((i, el) => el.nodeType == 3)[0].nodeValue;
$cat.text(value);
});
// Than, 3000 lines later... THANK YOU BECAUSE:
$('body').on('click', function() {
// Close a popup or something
console.clear(); console.log(`YEY I registered an event!
Thank you for not using Event.preventDefault()`);
});
.cat-list,
.sub-list {
display: none;
}
<div class="form-group">
<label for="input-placeholder" class="col-sm-2 control-label"></label>
<div class="col-sm-10">
<div class="cat-group">
<button class="cat-select" type="button">Select Category</button>
<ul class="cat-list">
<li class="have-child">Electronics
<ul class="sub-list">
<li class="have-child"> Mobiles & Tablets
<ul class="sub-list">
<li>Mobiles</li>
<li>Tablets</li>
<li class="have-child">Accessories</li>
<ul>
<li>Power Bank</li>
<li>Phone Cases</li>
</ul>
</ul>
</li>
<li class="have-child">Cameras
<ul class="sub-list">
<li>DSLRs</li>
<li>Drones</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Get the clicked element based the event.target property. Although you can avoid the clone by contents() and filter() methods which help to filter out text nodes.
$(document).on('click', 'li', function(e) {
// if target element is not `li` tag then get closest li tag
var selectedVal = (e.target.nodeType == 'LI' ? $(e.target) : $(e.target).closest('li'))
.contents() // get all children nodes
.filter(function() { // filter out text nodes
return this.nodeType === 3;
}).text(); // get text content
$('.cat-select').text(selectedVal);
})
$(document).on('click', 'li', function(e) {
// if target element is not `li` tag then get closest li tag
var selectedVal = (e.target.nodeType == 'LI' ? $(e.target) : $(e.target).closest('li'))
.contents() // get all children nodes
.filter(function() { // filter out text nodes
return this.nodeType === 3;
}).text(); // get text content
$('.cat-select').text(selectedVal);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="form-group">
<label for="input-placeholder" class="col-sm-2 control-label"></label>
<div class="col-sm-10">
<div class="cat-group">
<button class="cat-select" type="button">
Select Category</button>
<ul class="cat-list">
<li class="have-child">Electronics
<ul class="sub-list">
<li class="have-child">Mobiles & Tablets
<ul class="sub-list">
<li>Mobiles</li>
<li>Tablets</li>
<li class="have-child">Accessories</li>
<ul>
<li>Power Bank</li>
<li>Phone Cases</li>
</ul>
</ul>
</li>
<li class="have-child">Cameras
<ul class="sub-list">
<li>DSLRs</li>
<li>Drones</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>

i hope this one is helping u
$('.cat-select').each(function() {
$(this).on('click', function() {
$('.cat-list').css('display', 'block');
$('.sub-list').css('display', 'block');
});
});
$(document).on('click', function() {
$(this).each('.cat-list li', function() {
var selectedVal = $(this).clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.text(); //get the text of elemen
console.log(selectedVal);
$('.cat-select').text(selectedVal);
});
});

Related

Get href value while clicking li tag

Following is the code of the Div which is created dynamically.
<div align="right" class="row pagination">
<ul class="pagination pagination">
<li class="prev disabled"><span>Previous Label</span></li>
<li class="active"><span>1</span></li>
<li>2</li>
<li>3</li>
<li class="next">Next Label</li>
</ul>
</div>
When I click any <li> tag, I need to take the href value(eg: /some_url?page=2) of corresponding <li> tag.
$("ul.pagination li").click(function(e) {
alert($(this).attr('href'));
});
In the above code, clicking event is firing but i am getting undefined in the alert.
Please help.
but i am getting undefined in the alert.
Yes because you're trying to alert the href of the clicked li when it has no attribute href.
You need to alert the href of the anchor inside the li using a in your selector, or also using .find() like :
alert( $('a', this).attr('href') );
//Or also
alert( $(this).find('a').attr('href') );
You could also attach the click event directly to the child anchors of the il's like :
$("ul.pagination li a").click(function(e) {
alert( $(this).attr('href') );
});
$("ul.pagination li").click(function(e) {
alert($('a', this).attr('href'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div align="right" class="row pagination">
<ul class="pagination pagination">
<li class="prev disabled"><span>Previous Label</span></li>
<li class="active"><span>1</span></li>
<li>2</li>
<li>3</li>
<li class="next">Next Label</li>
</ul>
</div>
here is a technique very close to what you had:
$("ul.pagination li a").click(function(e) {
alert($(this).attr('href'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div align="right" class="row pagination">
<ul class="pagination pagination">
<li class="prev disabled"><span>Previous Label</span></li>
<li class="active"><span>1</span></li>
<li>2</li>
<li>3</li>
<li class="next">Next Label</li>
</ul>
</div>
$(this) inside your function call is referring to li element and not the a. You need to find a inside li and then get the attribute href like this
$("ul.pagination li").click(function(e) {
alert($(this).find('a').attr('href') );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div align="right" class="row pagination">
<ul class="pagination pagination">
<li class="prev disabled"><span>Previous Label</span></li>
<li class="active"><span>1</span></li>
<li>2</li>
<li>3</li>
<li class="next">Next Label</li>
</ul>
</div>
because elements are created dynamically,
You should provide a selector to the on function:
$(document).on('click', 'ul.pagination li', function(e) {
alert($(this).children('a').attr('href'));
});
children() vs find()
The .children() method differs from .find() in that .children() only travels a single level down the DOM tree while .find() can traverse down multiple levels to select descendant elements (grandchildren, etc.) as well

jQuery click on a inside of ul and get it's attribute

I need to register click on the element a in ul list and get id of the a.
$("#nativeLang > ul > li > a").click(function(){
alert($(this).attr("id"));
});
This code is not working.
I found another way:
$("#nativeLang > ul").on("click", "a", function(event){
alert($(this).attr("id"));
});
But here I cannot get id of the clicked element a.
HTML
<li class="dropdown" id="nativeLang">
<ul class="dropdown-menu">
<li>English</li>
</ul>
</li>
If you're dynamically inserting these <li> tags, then you need to use $(document).on(...);
$(document).on("click", "#nativeLang > ul > li > a", function( event ){
$('#Result').html( $(this).attr("id") );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li class="dropdown" id="nativeLang">
<ul class="dropdown-menu">
<li>English</li>
</ul>
</li>
<div id="Result" ></div>
HTML:
<li class="dropdown" id="nativeLang">
<ul class="dropdown-menu">
<li>English</li>
</ul>
</li>
JS:
$("#nativeLang > ul").on('click', 'a', function(){
alert(this.id);
});
CODEPEN DEMO

Show the content based on link click. And hide previously selected

I want to show the content based on link click. and hide the content which was previously selected.
Any way to do it?
Note : I dont want to change the markup.
Here is jsFiddle
html:
<ul class="nav nav-stacked" id="nav-stacked">
<li class="active"><i class="fa fa-dashboard fa-fw"></i>Dashboard
</li>
<li id="vollist-container" class="menu open"><i class="fa fa-sort-alpha-asc fa-fw"></i>Volumes<i class="caret"></i>
<ul id="vol-list" class="submenu">
<li> <a href="javascript:void(0);" onclick="show_content('vol1', this)">
<span>vol1</span>
</a>
</li>
<li> <a href="javascript:void(0);" onclick="show_content('vol2', this)">
<span>vol2</span>
</a>
</li>
</ul>
</li>
</ul>
<div id="content">
<div id="dashboard" class='show'>dashboard</div>
<div id="volumes">
<div id="vol1" class="hide">vol 1</div>
<div id="vol2" class="hide">vol 2</div>
</div>
</div>
jQuery:
function show_content(id, element) {
var children = $("#content").children();
children.filter(function () {
return $(this).css('display') == 'block';
}).hide();
$("#" + id).parent().css('display') == 'none' ? $("#" + id).parent().show() : null;
$("#" + id).toggleClass('hide');
}
This function does what you need:
function show_content(id, element) {
$('#content > div').hide();
$('#' + id).show();
}
Notes:
You do not need the .show and .hide CSS classes
You still need to hide all the content divs on page load either via CSS or via jQuery.
The element parameter is not necessary.
jQuery offers more elegant ways to solve this problem, but the function above should answer your question.
<script>
function showSomething()
{
$("#div1").hide();
$("#div2").show();
</script>
Around your div:
<a href="Javascript:showSomething();">
<div></div>
</a>

JQuery class vs ID

I have a foreach loop here. For every item it prints, there is a comment section that is expandable/collapsable.
The problem I have is, when I hit the "Expand All" for an item, it expands the comments for EVERY item in the loop all at once. Whereas, I only want to see the comments for that specific item.
I know it has something to do with IDs and Classes, but I have zero experience with JQuery. So please help!
<?php
foreach ($items as $item) {
echo item['comment'];
echo $item['full_name']; ?>
<div id="listContainer">
<div class="listControl">
<a class="expandList">Expand All</a>
<a class="collapseList">Collapse All</a>
</div>
<ul class="expList">
<li>Item A
<ul>
<li>Item A.1
<ul>
<li><span>fidjis</span></li>
</ul>
</li>
<li>Item A.2</li>
<li>Item A.3
<ul>
<li><span>iejowejfiojwiefj.</span></li>
</ul>
</li>
</ul>
</li>
<li>Item B</li>
<li>Item C
<ul>
<li>Item C.1</li>
<li>Item C.2
<ul>
<li><span>sdfkjksdjfnjkdsfnjn</span></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<?php
}
?>
and here is the Jquery:
function prepareList() {
$('.expList').find('li:has(ul)')
.click( function(event) {
if (this == event.target) {
$(this).toggleClass('expanded');
$(this).children('ul').toggle('medium');
}
return false;
})
.addClass('collapsed')
.children('ul').hide();
//Create the button functionality
$('.expandList')
.unbind('click')
.click( function() {
$('.collapsed').addClass('expanded');
$('.collapsed').children().show('medium');
})
$('.collapseList')
.unbind('click')
.click( function() {
$('.collapsed').removeClass('expanded');
$('.collapsed').children().hide('medium');
})
};
You are creating the DIV with ID "listContainer" on every iteration of your loop, this is invalid. An ID should only be used once.
Would suggest changing the Id="listContainer" to class="listContainer"
For the jQuery, the problem is that you are referencing all elements with the 'collapsed' class, rather than just the ones that are within the container relating to the Expand All button.
I haven't tested this, but you would want something along these lines
//Create the button functionality
$('.expandList')
.unbind('click')
.click( function() {
$(this).parents('.listContainer').find('.collapsed').addClass('expanded');
$(this).parents('.listContainer').find('.collapsed').children().show('medium');
})
$('.collapseList')
.unbind('click')
.click( function() {
$(this).parents('.listContainer').find('.collapsed').removeClass('expanded');
$(this).parents('.listContainer').find('.collapsed').children().hide('medium');
})
The difference here is that you start from the button clicked and div with the 'listContainer' class, then work down from there to find all the '.collapsed' elements.
First you should change listContainer into a class attribute.
as ID´s must be unique.
function prepareList() {
$('.expList').find('li:has(ul)')
.click( function(event) {
if (this == event.target) {
$(this).toggleClass('expanded');
$(this).children('ul').toggle('medium');
}
return false;
})
.addClass('collapsed')
.children('ul').hide();
//Create the button functionality
$('.expandList')
.unbind('click')
.click( function() {
// walk up the tree from the clicked button
// and find the parent .listContainer
var $list = $(this).parents(".listContainer");
// find .collapsed in .listContainer
$list.find('.collapsed').addClass('expanded');
$list.find('.collapsed').children().show('medium');
});
$('.collapseList')
.unbind('click')
.click( function() {
// walk up the tree from the clicked button
// and find the parent .listContainer
var $list = $(this).parents(".listContainer");
// find .collapsed in .listContainer
$list.find('.collapsed').removeClass('expanded');
$list.find('.collapsed').children().hide('medium');
});
};
I think you are using classes in place for ID. IDs are used to identify a single elements whereas a class can be applied to more that 1 element. Try to use IDs in your jQuery calls when accessing an individual element. You can try something like:
?>
<div id="listContainer">
<div class="listControl">
<a class="expandList">Expand All</a>
<a class="collapseList">Collapse All</a>
</div>
<ul id="list1" class="expList">
<li>
Item A
<ul>
<li>
Item A.1
<ul>
<li>
<span>fidjisjfisdjfisdjifjsidfj.</span>
</li>
</ul>
</li>
<li>
Item A.2
</li>
<li>
Item A.3
<ul>
<li>
<span>iejowejfiojwiefj.</span>
</li>
</ul>
</li>
</ul>
</li>
<li>
Item B
</li>
<li>
Item C
<ul>
<li>
Item C.1
</li>
<li>
Item C.2
<ul>
<li>
<span> sdfkjksdjfnjkdsfnjn. </span>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<?php
}
?>
and your jQuery will be something like
function prepareList() {
$('#list1').find('li:has(ul)')
.click( function(event) {
if (this == event.target) {
$(this).toggleClass('expanded');
$(this).children('ul').toggle('medium');
}
return false;
})
.addClass('collapsed')
.children('ul').hide();
//Create the button functionality
$('.expandList')
.unbind('click')
.click( function() {
$('.collapsed').addClass('expanded');
$('.collapsed').children().show('medium');
})
$('.collapseList')
.unbind('click')
.click( function() {
$('.collapsed').removeClass('expanded');
$('.collapsed').children().hide('medium');
})
};

How to create a sitemap using jQuery

I have following markup
<div id="mnuMain">
<ul>
<li>Dashboard</li>
<li>Market Trends</li>
<li>Master
<ul>
<li>Products</li>
<li>Segments</li>
<li><a href="#" >Companies</a></li>
</ul>
</li>
<li>Settings
<ul>
<li>Dashboard Settings</li>
</ul>
</li>
</ul>
<br style="clear: left" />
</div>
<div id="divNavigation" style="height:20px;width:100%;
background:gray;color:white">
</div>
My question is
How to track parents upward when I click on particular <a> so that divNavigation
will contain suppose now I have clicked on "Segments" divNavigation should have Master > Segments with links.
rushed codes
$(function() {
$('#mnuMain ul li a').click(function() {
var $li = $(this).parents('li');
var container = $('#divNavigation').empty();
$li.each(function(i) {
if (i > 0) {
$('<span>></span>').prependTo(container);
}
$(this).children('a:first').clone().prependTo(container);
});
return false;
});
});​
demo
$("#mya").parent() for accessing the immediate parent. Use parents() for accessing all ancestors. This is if you have id. If you don't then you may need something like this:
$("a").each( var parent = $(this).parent(); <use parent to do stuff>);

Categories

Resources