jquery dynamic filter list - javascript

I'm trying to make a filter list on keypress. For example if I write in input "It", the elements that doesn't match this input value are hidden. I'm not sure if the idea I have with code below does the job. Any tips will be highly appreciated!
$('ul li ul li').addClass('displayNone');
var geInputValue = $('input').val();
var getInputLength = $('input').length;
function sortDynamically(){
$('input').on('keypress', function(){
for(var i=0; i < getInputLength; i++){
if(getInputValue === $('li').text){
// remove everything that doesnt match input value
$('li').siblings().addClass('displayNone');
}
else{
$('li').siblings().removeClass('displayNone');
});
}
sortDynamically();
ul, li{
list-style-type: none;
margin: 0;
padding: 0;
}
.displayNone{
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" />
<ul class="list">
<li>Item</li>
<li>Product
<ul>
<li>Bike</li>
</ul>
</li>
<li>About</li>
</ul>

This code filters based on what you type. If there is nothing in the text input then everything is shown.
$('input').on('keypress keyup', function(){
var value = $(this).val().toLowerCase();
if (value != '') {
$('.list > li').each(function () {
if ($(this).text().toLowerCase().indexOf(value) > -1) {
$(this).removeClass('displayNone');
} else {
$(this).addClass('displayNone');
}
});
} else {
$('.list > li').removeClass('displayNone');
}
});
ul, li{
list-style-type: none;
margin: 0;
padding: 0;
}
.displayNone{
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" />
<ul class="list">
<li>Item</li>
<li>Product
<ul>
<li>Bike</li>
</ul>
</li>
<li>About</li>
</ul>

jQuery provides filters and javascript implements toLowerCase() and includes() methods that you can use to improve your code
<body>
<style>
.displayNone
{
display: none;
}
</style>
<input type="text" id="input-filter"/>
<ul class="list">
<li>Item</li>
<li>Product
<ul>
<li>Bike</li>
</ul>
</li>
<li>About</li>
</ul>
<script>
var items = $('ul.list li');
$('#input-filter').on('input', function ($event)
{
items.addClass('displayNone').filter(function (item)
{
return $(this).text().toLowerCase().includes($($event.target).val().toLowerCase());
}).removeClass('displayNone');
});
</script>
</body>

Related

How to know the logic of multilevel menu event bubbling

I'm trying to understand the logic happening in my basic multilevel menu click event. I understood what happening on clicking on "About" menu in the navigation. And it works as per my expecation of code. But when i click on "Profile" menu (Submenu of "About" menu), JS makes it's sublevel menu "display:none". I tried to think in the aspect of even bubbling. But eventhough the bubbling happens here, it should not be working like this. Actually for me, its really complicated to understand how JS works here. It would be a Great Help if anyone can explain with a simple and understandable way. Thank You Very Much in Advance!!!
let menus = document.querySelectorAll(".main-navigation ul li a");
menus.forEach((item) => {
if (item.parentElement.querySelector("ul")) {
item.parentElement.classList.add("has-submenu");
}
});
let submenu = document.querySelectorAll(".has-submenu");
submenu.forEach((item) => {
item.addEventListener("click", (e) => {
e.preventDefault();
let ul = e.target.parentElement.querySelector("ul");
let cs = window.getComputedStyle(ul).display;
if (cs === "none") {
ul.style.cssText = "display:block";
}
else {
ul.style.cssText = "display:none";
}
});
});
.main-navigation ul {list-style:none;margin:0;padding:0;font-family:arial;}
.main-navigation ul li {padding:.35rem;background:#f9f9f9;}
.main-navigation ul li ul {padding-left:1rem;display:none;}
.main-navigation ul li a {display:block;text-decoration:none;}
<div class="main-navigation">
<ul>
<li>Home</li>
<li>About +
<ul>
<li>Profile +
<ul>
<li>History</li>
<li>Management</li>
</ul>
</li>
<li>Vision</li>
<li>Mission</li>
</ul>
</li>
<li>Services +
<ul>
<li>Web Design</li>
<li>Web Development</li>
</ul>
</li>
<li>Contact</li>
</ul>
</div>
Solution
If you add a console.log inside your click handler you will notice that the event for the nested item is called twice.
You probably knew that it could happen and you used preventDefault.
However, preventDefault is for the browser's default effects (for example, it prevents your page to refresh as you put an href attribute) but in your case the double behaviour is from your own custom listener.
This means, you need to add stopPropagation that prevents further propagation of the current event in the capturing and bubbling phases.
Working Demo
let menus = document.querySelectorAll(".main-navigation ul li a");
menus.forEach((item) => {
if (item.parentElement.querySelector("ul")) {
item.parentElement.classList.add("has-submenu");
}
});
let submenu = document.querySelectorAll(".has-submenu");
submenu.forEach((item) => {
item.addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
let ul = e.target.parentElement.querySelector("ul");
let cs = window.getComputedStyle(ul).display;
if (cs === "none") {
ul.style.cssText = "display:block";
} else {
ul.style.cssText = "display:none";
}
});
});
.main-navigation ul {
list-style: none;
margin: 0;
padding: 0;
font-family: arial;
}
.main-navigation ul li {
padding: .35rem;
background: #f9f9f9;
}
.main-navigation ul li ul {
padding-left: 1rem;
display: none;
}
.main-navigation ul li a {
display: block;
text-decoration: none;
}
<div class="main-navigation">
<ul>
<li>Home</li>
<li>About +
<ul>
<li>Profile +
<ul>
<li>History</li>
<li>Management</li>
</ul>
</li>
<li>Vision</li>
<li>Mission</li>
</ul>
</li>
<li>Services +
<ul>
<li>Web Design</li>
<li>Web Development</li>
</ul>
</li>
<li>Contact</li>
</ul>
</div>

How to target a div with a same ID

I currently have some ASP.Net code that builds an output and then displays it through a string literal. The idea is that for every Receipt, there is a 'view more' button which toggles extra information that is display: none; to start with. I tried to use the eq() method to attempt to find which one I wanted to toggle because I am doing that inside the ul. My current code is this:
$("#btn-expand").click(function () {
var ldx = $("#list li .active").index(); // Get the list number so we know what ID to work with
var idx = $("#expand").next().index(); // Get the next ID index point
// Check that it isn't going negative
if (idx == -1 || ldx == -1) {
// If it is, reset ldx
ldx = 0;
idx = 0;
}
$("#expand").eq(ldx).toggle(); // Toggle that one
console.log(ldx);
});
The first button works fine and console.log shows 0 however, all the others do not show anything. A sample of my HTML looks like this:
<ul id="list">
<li class="active">
Something <br />
Something Again <br />
<span id="btn-expand">[View more]</span>
<div id="expand">
Something hidden
</div>
</li>
This <br />
Shows <br />
<span id="btn-expand">[View more]</span>
<div id="expand">
This is hidden until toggled
</div>
<li></li>
</ul>
There is a lot more li elements in the ul but that is how it is structured. I am also using <span class="btn" id="btn-next">Next</span> to loop through each li in the ul so I am really confused why the same method for doing it with the `#expand' won't work.
If anyone could point me in the right direction, I'd be appreciated. Thanks.
$(document).ready(function() {
$("#btn-next").click(function() {
var $list = $("#list li");
var idx = $(".active").removeClass("active").next().index();
if (idx == -1) {
idx = 0;
}
$list.eq(idx).addClass("active");
});
$("#btn-prev").click(function() {
var $list = $("#list li");
var idx = $(".active").removeClass("active").prev().index();
if (idx == -1) {
idx = 0;
}
$list.eq(idx).addClass("active");
});
$("#btn-expand").click(function() {
// Get the list number so we know what ID to work with
var ldx = $("#list li .active").index();
// Get the next ID index point
var idx = $("#expand").next().index();
// Check that it isn't going negative
if (idx == -1 || ldx == -1) {
// If it is, reset ldx
ldx = 0;
idx = 0;
}
// Toggle that one
$("#expand").eq(ldx).toggle();
console.log(ldx);
});
});
#list {
list-style: none;
}
.active {
display: block;
}
#btn-expand {
cursor: pointer;
font-size: 9px;
margin-left: 10px;
}
#expand {
display: none;
}
li {
display: none;
}
.btn {
background: none;
padding: 10px;
border: 1px solid #000;
margin-left: 50px;
cursor: pointer;
}
<script src="//code.jquery.com/jquery-1.12.0.min.js"></script>
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<ul id="list">
<li class="active">
Something here
<br />Something here again
<span id="btn-expand"> [View More] </span>
<br />
<br />
<span id="expand">
This is hidden, shh..
</span>
</li>
<li>
You can see this
<br />Toggling shouldn't effect me
<span id="btn-expand"> [View More] </span>
<br />
<br />
<span id="expand">
But toggling should effect me!
</span>
</li>
</ul>
<span class="btn" id="btn-prev">Prev</span> - <span class="btn" id="btn-next">Next</span>
id should be unique in same document, replace the duplicate ones by general class, r.g :
<ul id="list">
<li class="active">
Something <br />
Something Again <br />
<span class="btn-expand">[View more]</span>
<div class="expand">
Something hidden
</div>
</li>
This <br />
Shows <br />
<span class="btn-expand">[View more]</span>
<div class="expand">
This is hidden until toggled
</div>
<li>
</li>
</ul>
Then replace id selector # in you script by class selector . :
$(".btn-expand").click(function() {
// Get the list number so we know what ID to work with
var ldx = $("#list li .active").index();
// Get the next ID index point
var idx = $(".expand").next().index();
// Check that it isn't going negative
if (idx == -1 || ldx == -1) {
// If it is, reset ldx
ldx = 0;
idx = 0;
}
// Toggle that one
$(".expand").eq(ldx).toggle();
console.log(ldx);
});
You could use just next() instead of all the code in your event :
$(this).next(".expand").toggle();
//OR
$(this).next().toggle();
Hope this helps.
$(".btn-expand").click(function() {
$(this).next(".expand").toggle();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="list">
<li class="active">
Something <br />
Something Again <br />
<span class="btn-expand">[View more]</span>
<div class="expand">
Something hidden
</div>
</li>
<li>
This <br />
Shows <br />
<span class="btn-expand">[View more]</span>
<div class="expand">
This is hidden until toggled
</div>
</li>
</ul>
Change id's to classes and all you need then is:
$(".btn-expand").click(function() {
$(this).next().toggle();
$(this).text(function(_, oldText){
return oldText.indexOf('More') === -1 ? 'View More' :'View Less';
})
});
$(document).ready(function() {
$("#btn-next").click(function() {
var $list = $("#list li");
var idx = $(".active").removeClass("active").next().index();
if (idx == -1) {
idx = 0;
}
$list.eq(idx).addClass("active");
});
$("#btn-prev").click(function() {
var $list = $("#list li");
var idx = $(".active").removeClass("active").prev().index();
if (idx == -1) {
idx = 0;
}
$list.eq(idx).addClass("active");
});
$(".btn-expand").click(function() {
// Toggle
$(this).next().toggle();
});
});
#list {
list-style: none;
}
.active {
display: block;
}
#btn-expand {
cursor: pointer;
font-size: 9px;
margin-left: 10px;
}
li {
display: none;
}
.btn {
background: none;
padding: 10px;
border: 1px solid #000;
margin-left: 50px;
cursor: pointer;
}
.expand-inner {
display:inline-block;
width:100%;
}
<script src="//code.jquery.com/jquery-1.12.0.min.js"></script>
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<ul id="list">
<li class="active">
Something here
<br />Something here again
<span class="btn-expand"> [View More] </span>
<span style="display:none;">
<div class="expand-inner">This is hidden, shh..</div>
</span>
</li>
<li>
You can see this
<br />Toggling shouldn't effect me
<span class="btn-expand"> [View More] </span>
<span style="display:none;">
<div class="expand-inner">But toggling should effect me!</div>
</span>
</li>
</ul>
<span class="btn" id="btn-prev">Prev</span> - <span class="btn" id="btn-next">Next</span>

Change background color on anchor in listitem when clicked

I have menu constructed by ul li with anchor tags in each. Css is applied to the anchor
and anchor:hover however I want the selected item to show that it is selected be changing the background a different color. anchor:active does not work.
I am trying javascript but not yet successful. Can this be soley done through css? I have looked at so many examples, but none actually worked right.
JAVASCRIPT
<script type="text/javascript">
function ChangeColor(obj) {
var li = document.getElementById(obj.id);
li.style.background = "#bfcbd6";
}
</script>
HTML
<div id="navigation">
<ul>
<li><a onclick="changecolor(this);" href="Default.aspx">Home</a></li>
<li><a onclick="changecolor(this);" href="View.aspx">View</a></li>
<li><a onclick="changecolor(this);" href="About.aspx">About</a></li>
</ul>
</div>
CSS - Simplified
#navigation ul {
list-style-type: none;
}
#navigation li
{
float: left;
}
#navigation a
{
background-color: #465c71;
}
#navigation a:hover
{
background-color: #bfcbd6;
}
you don't need to get id again for handling element. obj references the actual element.
<script type="text/javascript">
function ChangeColor(obj) {
obj.style.backgroundColor = "#bfcbd6";
}
</script>
Edit: And javaScript is case sensitive, so you should check your function names.
Here is a jsFiddle Demo
I have found a way to use JavaScript to solve this situation. This works for having MasterPage. Changing the id of the selected tab will then reference the css for that
selected tab only while setting the other tabs id's to null.
HTML
<div id="navbar">
<div id="holder">
<ul id="menulist">
<li><a onclick="SelectedTab(this);" href="#" id="onlink" >Home</a></li>
<li><a onclick="SelectedTab(this);" href="#" id="" >Products</a></li>
<li><a onclick="SelectedTab(this);" href="#" id="">Services</a></li>
<li><a onclick="SelectedTab(this);" href="#" id="">Gallery</a></li>
<li><a onclick="SelectedTab(this);" href="#" id="" >Contact</a></li>
</ul>
</div>
</div>
JavaScript
function SelectedTab(sender) {
var aElements = sender.parentNode.parentNode.getElementsByTagName("a");
var aElementsLength = aElements.length;
var index;
for (var i = 0; i < aElementsLength; i++)
{
if (aElements[i] == sender) //this condition is never true
{
index = i;
aElements[i].id="onlink"
} else {
aElements[i].id=""
}
}
}
Css for changing the background color after tab has been selected
#holder ul li a#onlink
{
background: #FFF;
color: #000;
border-bottom: 1px solid #FFF;
}

when click on the first li, it show content one, when click on second li, it shows content two

<style type="text/css">
.web_index div {width: 400px; height: 300px; background: #eee;}
ul li{width: 100px; height: 30px; line-height: 30px; list-style: none; display: inline-block; *display: inline; zoom: 1;}
</style>
<script type="text/javascript">
function licker(){
var lier=document.getElementsByTagName("li");
var diver=document.getElementsByClassName("web_index")[0].getElementsByTagName("div");
for(var i=0;i<lier.length;i++)
{
for(j=0;j<diver.length;j++)
{
if(i==j)
{
diver[j].style.display=block;
}
else{
diver[j].style.display=none;
}
}
}
}
</script>
html:
<ul>
<li onclick="licker()" class="li01">the first li</li>
<li onclick="licker()" class="li02">the second li</li>
<li onclick="licker()" class="li03">the third li</li>
<div class="web_clear"></div>
</ul>
<div class="web_index">
<div style="display:block" >content one</div>
<div style="display:none">content two</div>
<div style="display:none">content three</div>
</div>
when click on the first li, it show content one, the others are all hidden, when click on second li, it shows content two. the others are all hidden....why my code doesn't work.how to correct it.thank you,
You should assign an index to your li's:
<ul>
<li onclick="licker(0)" class="li01">the first li</li>
<li onclick="licker(1)" class="li02">the second li</li>
<li onclick="licker(2)" class="li03">the third li</li>
<div class="web_clear"></div>
</ul>
and your function:
function licker(id){
var diver=document.getElementsByClassName("web_index")[0].getElementsByTagName("div");
for(var i=0;i<diver.length;i++){
if(i==id){
diver[i].style.display='block';
} else {
diver[i].style.display='none';
}
}
}​
JSFiddle Example
Try this
<ul>
<li onclick="licker(this);">the first li</li>
<li onclick="licker(this);">the second li</li>
<li onclick="licker(this);">the third li</li>
</ul>
<div class="web_index">
<div style="display: block">content one</div>
<div style="display: none">content two</div>
<div style="display: none">content three</div>
function licker(sender) {
var lier = document.getElementsByTagName("li");
var diver = document.getElementsByClassName("web_index")[0].getElementsByTagName("div");
for (var i = 0; i < lier.length; i++) {
if (lier[i] != sender) continue;
for (j = 0; j < diver.length; j++) {
if (i == j)
diver[j].style.display = 'block';
else
diver[j].style.display = 'none';
}
}
}
</script>

Change class on a-element with Javascript

I'm fairly new to Javascript, and I've run into an issue which is annoying.
I have a list containing lists. I have a script that sets the list visible / invisible on click. However, I wan't to toggle / add a class to the link, once it has been pressed.
My list looks like this
<ul>
<li>Click something
<ul id="item1" style="display: none;">
<li>Something ...</li>
<li>Something something</li>
</ul></li>
<li>Click something else
<ul id="item2" style="display: none;">
<li>Something more...</li>
<li>Something something less?</li>
</ul></li>
</ul>
and my script looks like this:
<script type="text/javascript">
function toggle(id) {
var v = document.getElementById(id);
if (v.style.display == '') {
v.style.display = 'none';
v.removeClass("selected");
} else {
v.style.display = '';
v.addClass("selected");
}
}
</script>
The list shows and hides as it's supposed to, but the class is not added nor removed.
CSS is like this:
a:link {
color: #000000;
text-decoration: none;
}
a:hover, a.selected {
color: #005b97;
text-decoration: none;
padding-left: 2px;
}
Thanks in advance
Best Regards
Benjamin
js does not have an inbuilt add and remove class
Try this
To add a class
document.getElementById("MyElement").className += " MyClass";
To remove a class
document.getElementById("MyElement").className =
document.getElementById("MyElement").className.replace
( /(?:^|\s)MyClass(?!\S)/ , '' )
And if you need to check if an element has a class
function hasClass(ele,cls) {
return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
}
There's no addClass / removeClass in vanilla JavaScript.
Either you have to use HTML5 classList API or directly manipulate v.className.
Tried to do it with less code. Hoefully it does what you need it to do.
HTML:
<ul>
<li><a class="aSwitch" href="#" >Click something</a>
<ul id="item1" style="display:none">
<li>Something ...</li>
<li>Something something</li>
</ul></li>
<li><a class="aSwitch" href="#" >Click something else</a>
<ul id="item2" style="display:none">
<li>Something more...</li>
<li>Something something less?</li>
</ul></li>
​
CSS:
a:link {
color: #000000;
text-decoration: underline;
}
a.selected {
color: #005b97;
text-decoration: none;
padding-left: 2px;
}
​
jQuery
$('a.aSwitch').click(function() {
$(this).next().toggle();
$(this).toggleClass('selected');
});
See it working here: FIDDLE
document.getElementById("idElement").setAttribute("class", "className");
Most easily u can add jquery addon
<script src="../../Scripts/jquery-ui-1.8.11.min.js" type="text/javascript"></script>
Than change your code to
<script type="text/javascript">
function toggle(id) {
var v = document.getElementById(id);
$('#' + id).toggleClass("selected");
if (v.style.display == '') {
v.style.display = 'none';
} else {
v.style.display = '';
}
}
</script>

Categories