Changing Style of Parent LI in Collapsible Menu - javascript

This should be easy, but I'm having a hard time with it.
I have a simple collapsing menu that uses SPAN tags inside LI tags, the usual.
Here's the JavaScript:
var allSpan = document.getElementsByTagName('SPAN');
for (var i = 0; i < allSpan.length; i++) {
allSpan[i].onclick = function() {
if (this.parentNode) {
var childList = this.parentNode.getElementsByTagName('UL');
for (var j = 0; j < childList.length; j++) {
var currentState = childList[j].style.display;
if (currentState == "none") {
childList[j].style.display = "block";
} else {
childList[j].style.display = "none";
}
}
}
}
}
It works just fine in hiding and showing the nested ULs. What I'd like to do is add a piece of code that also changes the SPAN of the clicked-on parent LI item.
I'm thinking it would be something like:
if(currentState=="none") {
childList[j].style.display="block";
$(this).css('background-color', 'red');
}
else {
childList[j].style.display="none";
$(this).css('background-color', 'blue');
}
I'm sure I'm missing the obvious. Could somebody please point me in the right direction?
UPDATE
Sorry, I totally forgot there was more code at the bottom:
$(function() {
$('#menu').find('SPAN').click(function(e) {
$(this).parent().find('UL').toggle();
});
});
And here is the body of the HTML:
<style TYPE="text/css">
<!--
body { background: white;color: #000000;font-family:geneva; }
a:link { color: #ff8080 }
a:visited { color: #ff0000 }
a:active { color: #a05050 }
ul { margin:0;padding:0; }
li { list-style-type: none; }
ul li span { display:block;min-height:20px;background:blue;color:white;font-weight:bold;padding: 3px 8px 3px 8px;border-top:1px solid black;border-left:1px solid black;border-right:1px solid black;margin:0; }
li ul { display:none; }
li ul li span { background:#98ff33;padding: 3px 8px 3px 8px;color:black;font-weight:normal;display:block; }
li ul li:last-child span { border-bottom:1px solid black; }
-->
</style>
</head>
<body>
<UL id="menu">
<LI class="Category"><SPAN>Solid Tumors</SPAN><UL>
<LI class="subtopic"><SPAN>Anal Cancer</SPAN></LI>
<LI class="subtopic"><SPAN>Biliary Cancer</SPAN></LI>
<LI class="subtopic"><SPAN>Bladder Cancer</SPAN></LI>
</UL>
<LI class="Category"><SPAN>Hematologic Malignancies</SPAN><UL>
<LI class="subtopic"><SPAN>Acute Myeloid Leukemia</SPAN></LI>
<LI class="subtopic"><SPAN>Acute Promyelocytic Leukemia</SPAN></LI>
</UL>
<LI class="Category"><SPAN>Reviewers</SPAN><UL>
<LI class="subtopic"><SPAN>Physician Reviewers</SPAN></LI>
<LI class="subtopic"><SPAN>Pharmacy Reviewers </SPAN></LI>
</UL>
</UL>

A simple method would be to only toggle the class of the parent li element:
$(function () {
$('#menu SPAN').click(function (e) {
$(this).parent().toggleClass('open');
});
});
And then add then using CSS to manage the colors and the show/hide by adding the following css:
#menu li.open > span {
background-color: red
}
#menu li.open ul {
display: inline
}
see: http://jsfiddle.net/3TTDJ/
Note: if you only want to do this for the first menu level and not recursive, you'll want to specify that in the selector using immediate child selector '#menu > li > SPAN':
$(function () {
$('#menu > li > SPAN').click(function (e) {
$(this).parent().toggleClass('open');
});
});
see: http://jsfiddle.net/tleish/3TTDJ/2/

Below changes the span background color or the parent listitem
http://jsfiddle.net/tuusT/2/
$('#menu').find('SPAN').click(function(e){
$('#menu').find('.active').removeClass("active");
$(this).parents(".Category").children("span:first").addClass("active")
$(this).parent().find('UL').toggle();
});

Related

Making ul li dropdown filter

I have a dropdown menu, now trying to use it as a filter. pass a value when I click the menu item start filtering But I am a bit confused at Jquery part. How to pass "name" & "value" and start filtering. And the important issue is when I click one item and filter. After that when I click next item, I don't want it to start over. I want to keep old history of search. and add it to new filter.
var allOptions = $(".init").children('li');
$("ul").on("click", function() {
allOptions.removeClass('selected');
$(this).addClass('selected');
$("ul").children('.init').html($(this).html());
allOptions.slideUp();
});
#filter-wrapper
{
margin-top:15px
}
#filter-wrapper ul
{
list-style:none;
position:relative;
float:left;
margin:0;
padding:0
}
#filter-wrapper ul a
{
display:block;
color:#333;
text-decoration:none;
font-weight:700;
font-size:12px;
line-height:32px;
padding:0 15px;
font-family:"HelveticaNeue","Helvetica Neue",Helvetica,Arial,sans-serif
}
#filter-wrapper ul li
{
position:relative;
float:left;
margin:0;
padding:0
}
#filter-wrapper ul li.current-menu-item
{
background:#ddd
}
#filter-wrapper ul li:hover
{
background:#f6f6f6
}
#filter-wrapper ul ul
{
display:none;
position:absolute;
top:100%;
left:0;
background:#fff;
padding:0
}
#filter-wrapper ul ul li
{
float:none;
width:200px
}
#filter-wrapper ul ul a
{
line-height:120%;
padding:10px 15px
}
#filter-wrapper ul ul ul
{
top:0;
left:100%
}
#filter-wrapper ul li:hover > ul
{
display:block
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<div id="filter-wrapper">
<ul>
<li name="sortbyprice" class="current-menu-item">Cheapest Cars</li>
<li name="sortbyprice" class="current-menu-item">Newest Cars</li>
<li>Car Color
<ul class="init" name="sortbycolor">
<li data-value="red">Red</li>
<li data-value="black">Black</li>
<li data-value="silver">Silver</li>
</ul>
</li>
</ul>
</div>
For example, when I select Red then Car Color changed with the Red.
P.S: And by the way the name="" that I gave, it comes from Laravel controller. It contains the data.
And this is the old filter of mine. It's working with this. I can filter the data.
<form>
<select name="sortbyprice" class="custom-select custom-select-md" style="width: 100px;">
<option value="asc">cheapest</option>
<option value="desc">Expensive</option>
</select>
<select id="cars" name="cars" class="custom-select custom-select-md" style="width: 100px;">
<option value="" disabled selected>car colors</option>
<option value="red">red</option>
<option value="blue">blue</option>
<option value="black">black</option>
</select>
<button type="submit" name="button" class="btn btn-success" id="filter-btn">Filter</button>
</form>
Not sure whether this is what you want, but you can try the code below and tell me what you think
var mockData = [
{
make: 'a',
color: 'red',
price: 1000
},
{
make: 'a',
color: 'black',
price: 2000
},
{
make: 'b',
color: 'red',
price: 1
},
{
make: 'a',
color: 'silver',
price: 3000
},
{
make: 'c',
color: 'black',
price: 1500
},
{
make: 'a',
color: 'red',
price: 1500
}
];
var allOptions = $('.init').children('li');
// use an object to store the filter options selected by the user
// you can then use the information in this object to do the filtering
// by sending an AJAX request or just filter the already fetched data
var filterOptions = {
sortbycolor: '',
sortbymake: '',
sortbyprice: ''
};
$(allOptions).on('click', function () {
// get the items' data-value
var value = $(this)[0].dataset.value;
// select the corresponding <a> tag
var button = $(this).parent()[0].previousElementSibling;
// get the corresponding name attribute, e.g. sortbycolor
var type = $($(this).parent()[0]).attr('name');
// set the filterOptions
filterOptions[type] = value;
// change the displayed text of the filter when the user select something
$(button).text(function (idx, content) {
// here I choose using a colon ':' as the separator,
// you can use whatever you want
var colonIndex = content.indexOf(':');
// example for baseContent is 'Car Color'
var baseContent = content;
if (colonIndex > -1) {
baseContent = content.slice(0, colonIndex);
}
// e.g 'Car Color: red
return baseContent + ': ' + value;
});
allOptions.slideUp();
console.log('update filterOptions: ', filterOptions);
// filter the already fetched data
var filteredData = mockData.filter(function (val) {
var isValid = true;
if (isValid && filterOptions.sortbycolor) {
isValid = val.color === filterOptions.sortbycolor;
}
if (isValid && filterOptions.sortbymake) {
isValid = val.make === filterOptions.sortbymake;
}
return isValid;
});
// sort the data by price
// hard-code the sorting direction here for simplicity,
// you can set this dynamically with the onclick event
filterOptions.sortbyprice = 'asc';
if (filterOptions.sortbyprice === 'asc') {
filteredData.sort(function (a, b) {
return a.price - b.price;
});
} else if (filterOptions.sortbyprice === 'desc') {
filteredData.sort(function (a, b) {
return b.price - a.price;
});
}
console.log('filteredData: ', filteredData);
// or you can send an ajax request to the server,
// and let the server handle the filtering for you
// you have to set the keys and values inside
// the 'data' youself, below is just an example
// as I don't know what your server's API looks like
$.get({
url: 'url-to-your-server',
data: {
color: filterOptions.sortbycolor,
make: filterOptions.sortbymake
},
success: function (response) {
// do something with the response,
// maybe it contains the filtered result
// however, I am not sure how does your API look like
}
});
});
// to deal with the left over css style(display: none) introduced by .slideUp()
$('.dropdown').on('mouseenter', function () {
allOptions.css('display', 'block');
});
console.log('initial filterOptions: ', filterOptions);
#filter-wrapper {
margin-top: 15px
}
#filter-wrapper ul {
list-style: none;
position: relative;
float: left;
margin: 0;
padding: 0
}
#filter-wrapper ul a {
display: block;
color: #333;
text-decoration: none;
font-weight: 700;
font-size: 12px;
line-height: 32px;
padding: 0 15px;
font-family: "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif
}
#filter-wrapper ul li {
position: relative;
float: left;
margin: 0;
padding: 0
}
#filter-wrapper ul li.current-menu-item {
background: #ddd
}
#filter-wrapper ul li:hover {
background: #f6f6f6
}
#filter-wrapper ul ul {
display: none;
position: absolute;
top: 100%;
left: 0;
background: #fff;
padding: 0
}
#filter-wrapper ul ul li {
float: none;
width: 200px
}
#filter-wrapper ul ul a {
line-height: 120%;
padding: 10px 15px
}
#filter-wrapper ul ul ul {
top: 0;
left: 100%
}
#filter-wrapper ul li:hover>ul {
display: block
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="filter-wrapper">
<ul>
<li name="sortbyprice" class="current-menu-item">Cheapest Cars</li>
<li name="sortbyprice" class="current-menu-item">Newest Cars</li>
<li class="dropdown">
Car Color
<ul class="init" name="sortbycolor">
<li data-value="red">Red</li>
<li data-value="black">Black</li>
<li data-value="silver">Silver</li>
</ul>
</li>
<li class="dropdown">
Make
<ul class="init" name="sortbymake">
<li data-value="a">A</li>
<li data-value="b">B</li>
<li data-value="c">C</li>
</ul>
</li>
</ul>
</div>
I eliminated your css, you are just interested in the color value - correct ?
<div id="filter-wrapper">
<ul>
<li name="sortbyprice" class="current-menu-item">Cheapest Cars</li>
<li name="sortbyprice" class="current-menu-item">Newest Cars</li>
<li>Car Color
<ul class="init" name="sortbycolor">
<li>Red</li>
<li>Black</li>
<li>Silver</li>
</ul>
</li>
</ul>
</div>
<script>
var allOptions = $(".init").children('li');
// I think you are only interested in the html content of the a (anchor)
$("li[data-value] > a").on("click", function(e) {
e.preventDefault();
allOptions.removeClass('selected');
$(this).addClass('selected');
let filterVal = $(this).data('value'); // do something with this ...
let li = $('<li />').html( filterVal);
$("ul.init").html('').append( li); // ul.init just has the value of the filter
// allOptions.slideUp(); // superfluos
});
</script>

How to select each next() element of the list and unselect prev()?

I've been stuck with this one for quite awhile. Any help would be highly appreciated.
What I need is, once a client hits > arrow the current li element will be inactive, and next li element will be active. And the process will continue until the last li of the list will be the only active one.
Here is my jQuery code:
$(document).keyup(function(event) {
if (event.keyCode == 39){
$('#nav li .active').next().addClass('active').siblings().removeClass('active');
}
});
I am open to any suggestions and modifications of the code :)
You can use .each() (JQuery). syntax can be like this $('#nav li .active').each(function(index){Yourcodehere})
Feel free to comment.
What about something like this?
$(document).keyup(function(event){
if(event.keyCode == 39){
// Capture active li element
$active_li = $('#nav li.active');
// Clear active from all li elements
$('#nav li').each(function () {
this.removeClass('active');
});
// Set active for next li element
$active_li.next().addClass('active');
}
});
Or even maybe:
$(document).keyup(function(event){
if(event.keyCode == 39){
$('#nav li.active').removeClass('active').next().addClass('active');
}
});
Here's an example of a way to accomplish this. The markup will obviously be different. (JSFiddle below - be sure to click in the HTML frame before pressing the right arrow button):
https://jsfiddle.net/d13kwz1p/
Example HTML
<ul id="menu">
<li class="active">One</li>
<li>Two</li>
<li>Three</li>
</ul>
Example JS
var menu = $('#menu');
$(document).keyup(function(event) {
if (event.keyCode == 39) {
var current = menu.find('.active');
var next = current.next();
current.removeClass('active');
if (current.is(':last-child')) {
menu.find(':first-child').addClass('active');
} else {
next.addClass('active');
}
}
});
Example CSS:
#menu {
list-style: none;
margin: 0;
padding: 0;
}
#menu li {
background: #fff;
padding: 5px;
margin-bottom: 1px;
}
#menu li.active {
background: #ccc;
}

Get each scroll and increment active class

I want to make a custom slider on mousewheel event, my question is how can i do for get each scroll done on my page and add an active class on my 'ul li' and increment it one by one like:
if ($('scroll') === 1, function() {
$('ul li:first-child').addClass('active');
});
if ($('scroll') === 2, function() {
$('ul li:nth-child(2)').addClass('active');
});
ul li{
height:20px;
width:20px;
background:blue;
margin:5px;
list-style:none
}
ul li.active{
background:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="active"></li>
<li></li>
<li></li>
<li></li>
</ul>
Based on this answer: , you can do something like this:
var scrollable = $('ul li').length - 1,
count = 0;
$('body').bind('mousewheel', function(e) {
if (e.originalEvent.wheelDelta / 120 > 0) {
if (scrollable >= count && count > 0) {
$('.active').removeClass('active').prev().addClass('active');
count--
} else {
return false;
}
} else {
if (scrollable > count) {
$('.active').removeClass('active').next().addClass('active');
count++
} else {
return false;
}
}
})
ul li {
height: 20px;
width: 20px;
background: blue;
margin: 5px;
list-style: none
}
ul li.active {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="active"></li>
<li></li>
<li></li>
<li></li>
</ul>
This syntax doesn't work:
if (value === other value, function() {
});
The correct syntax for an if statement is as follows:
if (value === other value) {
// execute code in here
}
Also, you've got this:
$('scroll') === 1
Here, $('scroll') is a jQuery function that selects the <scroll> HTML element (which doesn't exist).
Instead, you can detect the page's scroll position in JavaScript using window.scrollY, which returns the number of pixels that the document is currently scrolled down from the top. For example:
if (window.scrollY < 100) {
$('ul li:first-child').addClass('active');
} else if (window.scrollY < 200) {
$('ul li:nth-child(2)').addClass('active');
}

How to change css li style with javascript?

I have like link like this:
My Button
and css style:
.tree li a:hover, .tree li a:hover+ul li a {
background: #c8e4f8; color: #000; border: 1px solid #94a0b4;
}
And my question is how to change this .tree style to another one? And if i click again the style return to the beginning style?
it can be done in plain javascript as below :
var id = 'myElementId';
var myClassName = " tree";
var d;
function changeClass() {
d = document.getElementById(id);
if (d.className == ' tree') {
d.className = d.className.replace(myClassName, "");
} else {
//d=document.getElementById('myElementId');
d.className = d.className.replace(myClassName, ""); // first remove the class name if that already exists
d.className = d.className + myClassName; // adding new class name
}
}
.tree {
background: #c8e4f8;
color: #000;
border: 1px solid #94a0b4;
}
<a id="myElementId" href="#" onclick="changeClass()">My Button</a>
now in jQuery it can be achieved using toggle as below :
var id = 'myElementId';
var myClassName = " tree";
function changeClass() {
$('#' + id).toggleClass(myClassName);
}
.tree {
background: #c8e4f8;
color: #000;
border: 1px solid #94a0b4;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<a id="myElementId" href="#" onclick="changeClass()">My Button</a>
Use classList.toggle("className") to toggle a class.
var div = document.getElementById("myDiv");
div.classList.toggle("myClassToggle");
Use this small javascript function:
function toggleClass(el, class1, class2) {
if(new RegExp("\\b"+class1+"\\b").test(el.className)) {
el.className = el.className.replace(new RegExp("\\b"+class1+"\\b",'g'),class2);
} else {
el.className = el.className.replace(new RegExp("\\b"+class2+"\\b",'g'),class1);
}
}
a {
display:block;
padding:10px;
color:white;
}
.myclass1 {
background:red;
}
.myclass2 {
background: green;
}
My Button
Edit: make sure that the classname is not in another word
A simple way to do this would be create another css class selector and assign to it your desired styles in the css file say .my-tree for example.
.my-tree {
color: red;
}
Now when your anchor is clicked you can add this css class to your tree element.
var treeEl = document.getElementById("tree");
treeEl.className = treeEl.className + " my-tree":
Similarly you can also remove this css class. You can use a variable in your code as a flag and use to add/remove the css class.
A simple way of doing this is to use the
toggleClass method of jquery which does this in a seamless manner.
Just going to throw this out there - you can do it in pure CSS:
[type=checkbox] {
display:none;
}
/* This selects the div tag immediately following the checkbox */
[type=checkbox] + div {
background:red;
cursor:pointer;
}
/* The same selector, except this is active when the checkbox is checked */
[type=checkbox]:checked + div {
background:blue;
color:#fff;
}
<label>
<input type="checkbox">
<div>Change me!</div>
</label>
This breaks a few rules for valid HTML, but if all you need is to toggle something (and not care about validation or quirksmode), this solution is pretty simple. If you do care about validation:
[type=checkbox] {
display:none;
}
[type=checkbox]:checked + label {
background:blue;
color:#fff;
}
[type=checkbox] + label {
background:red;
display:block;
}
<input id="toggler" type="checkbox">
<label for="toggler">
Change me!
</label>
Just something to chew on.
You can use jQuery
HTML:
My Button
JS:
$( "#myLink" ).click(function() {
$( "#myLink" ).toggleClass("first");
$( "#myLink" ).toggleClass("second");
});
CSS:
.first {
background: #c8e4f8; color: #000; border: 1px solid #94a0b4;
}
.second {
background: #000; color: #fff; border: 1px solid #94a0b4;
}

Creating a menu similar to Google Plus

I'm trying to achieve a responsive menu similar to Google Plus, where the main menu options are added to or removed from the "more" drop down as the window is resized.
The menu I have currently looks like this:
Here is the code:
// JQuery
$(document).ready(function() {
$("a.drop-menu").click(function () {
$('#drop-menu').toggle();
});
});
<!-- HTML -->
<ul id="navigation">
<li>Home</li>
<li>About</li>
<li>Calendar</li>
<li>Forum</li>
<li>Gallery</li>
<li>More
<ul id="drop-menu">
<li>Contact</li>
<li>Contact</li>
</ul></li>
</ul>
/* CSS */
#navigation {
list-style-type: none;
padding: 0px;
margin: 0px;
}
#navigation li {
display: inline-block;
}
#navigation li a:link, #navigation li a:visited, #navigation li a:active {
display: block;
width: 120px;
line-height: 50px;
text-align: center;
font-weight: bold;
text-decoration: none;
background-color: #27383F;
color: #CCC8C0;
}
#navigation li a:hover, #navigation li a.active {
background-color: #2C3C53;
}
#drop-menu {
display: none;
position: absolute;
padding: 0px;
margin: 0px;
}
#drop-menu li {
display: block;
}
JSFiddle
Currently, when the browser window is re-sized the menu options collapse as follows:
However, the below image is my desired result:
I'm wondering if there is a way to accomplish this without media queries? More specifically:
How can I dynamically detect whether the window size is large enough or too small to contain the li tags in the main navigation on a single line?
How do I swap the li tags between one menu and the other?
By not using media-queries I think you can use jQuery $( window ).width(); which will return width of browser viewport.. It should be like this:
$(document).ready(function() {
$("a.drop-menu").click(function () {
$('#drop-menu').toggle();
});
if($( window ).width() < $("#navigation > li").length * (120 + 5)){
//5px is the approximation of the gap between each <li>
var html = $("#navigation > li").last().prev().html();
$("#navigation > li").last().prev().remove();
$("#drop-menu").append(html);
}
var bigger = $("#navigation > li").length + 1;
var smaller = $("#navigation > li").length;
$( window ).resize(function() {
if($( window ).width() <= smaller * (120 + 5)){
//5px is the approximation of the gap between each <li>
var html = $("#navigation > li").last().prev().html();
if(html != undefined){
$("#navigation > li").last().prev().remove();
$("#drop-menu").prepend("<li>"+html+"</li>");
bigger = $("#navigation > li").length + 1;
smaller = $("#navigation > li").length;
}
}
if($( window ).width() >= bigger * (120 + 5)){
//5px is the approximation of the gap between each <li>
var html = $("#drop-menu > li").first().html();
if(html != undefined){
$("#drop-menu > li").first().remove();
$("#navigation > li").last().before("<li>"+html+"</li>");
bigger = $("#navigation > li").length + 1;
smaller = $("#navigation > li").length;
}
};
});
});
Check out this Fiddle, I believe it's not the perfect result.. But, I believe you can use it as your starting point.. Hope it helps..

Categories