Change class on a-element with Javascript - 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>

Related

Uncaught TypeError: Cannot read property 'add' of undefined at HTMLAnchorElement.linkAction

Showing me this:
Uncaught TypeError: Cannot read property 'add' of undefined at HTMLAnchorElement.linkAction
const navLink = document.querySelectorAll('.nav__link')
function linkAction(){
// Active
navLink.forEach(n => n.classList.remove('active'))
this.classlist.add('active')
// remove menu mobile
const navMenu = document.getElementById('nav-menu')
navMenu.classList.remove('show')
}
Here is the solution:
Typo: classList is case-sensitive:
You have this.classlist.add('active')
However, even correcting this typo wouldn't make code work, see point 2.
Missing argument at linkAction():
add the event as argument, in order to identify later which element triggered the function.
Hence, in your html: onclick="linkAction(event)"
then, in your JS: function linkAction(event){ ... event.target.classList.add('active')}
Following complete code sample: Run code snippet and see result:
const navLink = document.querySelectorAll('.nav__link');
// moved const assignment here outside of function
const navMenu = document.getElementById('nav-menu');
function linkAction(event){
// Active
navLink.forEach(n => n.classList.remove('active'));
// Typo: classList is case-sensitive
// this.classlist.add('active');
// following line does the trick :-)
event.target.classList.add('active');
// remove menu mobile
// better define 'const navMenu' outside this function
// to avoid multiple assignments
navMenu.classList.remove('show');
}
.nav__link {
color: #333;
margin: 1em;
background: #eee;
}
.nav__link:hover {
color: green;
background: #ddd;
}
.nav__link.active {
color: green;
background: lime;
}
#nav-menu {
display: none;
color: #333;
margin: 1em;
background: #eee;
}
#nav-menu.show {
display: block;
}
<div>click on any menu item below to trigger function</div>
<ul>
<li class="nav__link" onclick="linkAction(event)">item 1 with class "nav__link"</li>
<li class="nav__link" onclick="linkAction(event)">item 2 with class "nav__link"</li>
<li class="nav__link" onclick="linkAction(event)">item 3 with class "nav__link"</li>
</ul>
<div class="show" id="nav-menu">
Mobile menu
<ul>
<li class="nav__link" onclick="linkAction(event)">Mobile item 1</li>
<li class="nav__link" onclick="linkAction(event)">Mobile item 2</li>
<li class="nav__link" onclick="linkAction(event)">Mobile item 3</li>
</ul>
</div>

Change text color of a span with Javascript while hovering on seperated div

I have a menupoint and underneath it a seperate div / mega menu. I triggered the mega menu to show up via Javascript. When I am hovering over the mega menu, the desired span in the menu should get highlighted with another color and also the background color should change. You can see in the code how I tried to solve it (comments included). Can you please help me. I don´t know why I can´t trigger it via .getElementsByClassName!?
//Showing mega menu on hover over menu point
document.getElementById("menu-item-136").addEventListener("mouseover", mouseOver);
document.getElementById("menu-item-136").addEventListener("mouseout", mouseOut);
function mouseOver() {
document.getElementById("mega-menu").style.display = "block";
}
function mouseOut() {
document.getElementById("mega-menu").style.display = "none";
}
//Let mega menu stay visible when hovering over it
//Style menupoint when hovering over mega menu div (NOT WORKING)!
document.getElementById("mega-menu").addEventListener("mouseover", mouseOver);
document.getElementById("mega-menu").addEventListener("mouseout", mouseOut);
function mouseOver() {
document.getElementById("mega-menu").style.display = "block";
document.getElementsByClassName (".aux-menu-label").style.color = "yellow";
}
function mouseOut() {
document.getElementById("mega-menu").style.display = "none";
document.getElementsByClassName (".aux-menu-label").style.color = "";
}
.menu-item-136 {
background-color: grey;
height: 50px;
}
.menu-item-136:hover {
background-color:green;
}
.aux-menu-label {
color:blue;
}
.mega-menu-1 {
display: none;
background-color: green;
height: 200px;
}
<div>
<li id="menu-item-136" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-136 aux-menu-depth-0 aux-menu-root-2 aux-menu-item">
<a href="#" class="aux-item-content">
<span class="aux-menu-label"><i aria-hidden="true" class="services auxicon-list"></i> Leistungen</span>
<span class="aux-submenu-indicator"></span></a>
</div>
<div id="mega-menu" class="mega-menu-1">content</div>
Thanks for your help!
Your code is a bit messy but you are calling your class incorrectly:
This:
document.getElementsByClassName (".aux-menu-label")
Should be this:
document.getElementsByClassName ("aux-menu-label")
Additionally, when using getElementsByClassName you are provided with an array-like object with all elements that have the class you have specified.
With that in mind, you must run a loop to target elements with the styles you want to apply.
The below code is how we will target multiple labels and change them to yellow on hover:
var labels = document.getElementsByClassName("aux-menu-label");
for (var i = 0; i < labels.length; i++) {
labels[i].style.color = "yellow"
}
When you run the snippet below you will see I have used similar code to revert the color back to blue onmouseout.
Learn more about getElementsByClassName here.
//Including this to show you how to target CSS child elements as described in your comment
var childElement = document.querySelector('#menu-item-136 .aux-item-content');
childElement.style.backgroundColor = "white";
console.log(childElement);
//Showing mega menu on hover over menu point
document.getElementById("menu-item-136").addEventListener("mouseover", mouseOver);
document.getElementById("menu-item-136").addEventListener("mouseout", mouseOut);
function mouseOver() {
document.getElementById("mega-menu").style.display = "block";
}
function mouseOut() {
document.getElementById("mega-menu").style.display = "none";
}
//Let mega menu stay visible when hovering over it
//Style menupoint when hovering over mega menu div (NOT WORKING)!
document.getElementById("mega-menu").addEventListener("mouseover", mouseOver);
document.getElementById("mega-menu").addEventListener("mouseout", mouseOut);
function mouseOver() {
document.getElementById("mega-menu").style.display = "block";
var labels = document.getElementsByClassName("aux-menu-label");
for (var i = 0; i < labels.length; i++) {
labels[0].style.color = "yellow"
}
}
function mouseOut() {
document.getElementById("mega-menu").style.display = "none";
var labels = document.getElementsByClassName("aux-menu-label");
for (var i = 0; i < labels.length; i++) {
labels[i].style.color = "blue"
}
}
.menu-item-136 {
background-color: grey;
height: 50px;
}
.menu-item-136:hover {
background-color: green;
}
.aux-menu-label {
color: blue;
}
.mega-menu-1 {
display: none;
background-color: green;
height: 200px;
}
<div>
<li id="menu-item-136" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-136 aux-menu-depth-0 aux-menu-root-2 aux-menu-item">
<a href="#" class="aux-item-content">
<span class="aux-menu-label"><i aria-hidden="true" class="services auxicon-list"></i> Leistungen</span>
<span class="aux-submenu-indicator"></span></a>
</div>
<div id="mega-menu" class="mega-menu-1">content</div>
<div>
<li id="menu-item-136" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-136 aux-menu-depth-0 aux-menu-root-2 aux-menu-item">
<a href="#" class="aux-item-content">
<span class="aux-menu-label"><i aria-hidden="true" class="services auxicon-list"></i> Leistungen</span>
<span class="aux-submenu-indicator"></span></a>
</div>
<div id="mega-menu" class="mega-menu-1">content</div>
EDIT: I've included the following javascript to show you how to target child elements and apply CSS to them. The code below will target the child of #menu-item-136 and change its background color to white. Run the snippet to see.
var childElement = document.querySelector('#menu-item-136 .aux-item-content');
childElement.style.backgroundColor = "white";
console.log(childElement);
In your code
If we add some margin to megamenu wrapper This will be not working
and menu close when pointer out from menu item.
I have fixed that isseue
Its Looks like with WordPress menu. Please check below example and its will be helpful to use multiple mega-menues You need to map megamenu data id with menu class item.
codepen example
[].forEach.call(document.querySelectorAll('nav > ul > li'), function (link) {
link.addEventListener('mouseover', coloringHandler);
link.addEventListener('mouseout', decoloringHandler);
});
[].forEach.call(document.querySelectorAll('.megamenu'), function (menu) {
menu.addEventListener('mouseover', megamenuHover );
});
var state = false;
function coloringHandler(){
state = false;
hideAllMegamenu();
// add class to current hover element
this.classList.add('active');
var Classes = this.classList; // getting all class list
Classes.forEach(name => {
var megaMenu = document.querySelectorAll('[data-id="'+name+'"]'); // check if have any mached elements with class name
if(megaMenu.length == 1 ){
megaMenu[0].classList.add('active');
state = true;
megaMenu[0].addEventListener('mouseover', megamenuHover );
megaMenu[0].addEventListener('mouseout', megamenuHoverOut );
return;
}
});
}
function decoloringHandler(){
if( state == false ){
this.classList.remove('active');
hideAllMegamenu();
}
}
function hideAllMegamenu(){
// change elemets as you want
[].forEach.call(document.querySelectorAll('nav > ul > li'), function (li) {
li.classList.remove("active");
});
// .megamenu is common class
[].forEach.call(document.querySelectorAll('.megamenu'), function (menues) {
menues.classList.remove('active');
})
}
function megamenuHover() {
this.classList.add('in-hover');
}
function megamenuHoverOut() {
hideAllMegamenu();
}
nav ul{
display:flex;
list-style:none;
}
li{
margin:0px 10px;
}
a{
background:green;
display:block;
color:white;
padding:10px 20px;
}
ul li.active a{
background:red;
}
.megamenu{
background: red;
height:200px;
pointer-events: none;
opacity:0;
position:absolute;
width:100%;
padding:20px;
color:#fff;
transition:all .5s ease;
transform:translateY(50px);
}
.megamenu.active{
opacity:1;
pointer-events: all;
transform:translateY(0px);
}
<h1>Hover over the menu Items</h1>
<nav>
<ul>
<li class="menu-item-136">
<span>Home</span>
</li>
<li class="menu-item-137">
<span>Contact us</span>
</li>
<li class="menu-item-138">
<span>Danushka</span>
</li>
<li class="menu-item-139">
<span>About us</span>
</li>
</ul>
</nav>
<div class="megamenu" data-id="menu-item-137">
Lorem ipsum dolor sit amet consectetur adipisicing elit.
</div>
<div class="megamenu" data-id="menu-item-138">
Danushka Megamenu... Add data id for mapping
</div>

Add pagination to the filtering with slider, and show filtered content onload

I'm trying to change the code to following requirements.
Change the "prev" and "next" button to pagination (e.g. 1 2 3 4 and so on)
Show the "Category 1" content instead of show all contents. To display the filtered content onload as shown below. I did this but not sure is it good enough or not.
Actually I'm still not familiar with jQuery and javaScript. I have been trying to figure out the following code the past few weeks, but failed. Hoping that some of you could provide me with some advice. Thanks!
//Show filtred image onload
$(document).ready(function(){
$('div.filter a:first-child').trigger('click');
});
var visible = "";
$('div.filter').delegate('a', 'click', function (event) {
visible = '.' + this.href.slice(this.href.indexOf("#") + 1);
pagination();
event.preventDefault();
});
var itemsNumber = 8;
var min = 0;
var max = itemsNumber;
function pagination(action) {
var totalItems = $("li" + visible).length;
if (max < totalItems) {//Stop action if max reaches more than total items
if (action == "next") {
min = min + itemsNumber;
max = max + itemsNumber;
}
}
if (min > 0) {//Stop action if min reaches less than 0
if (action == "prev") {
min = min - itemsNumber;
max = max - itemsNumber;
}
}
$("li").hide();
$("li" + visible).slice(min, max).show();
}
pagination();
//Next
$("#next").click(function() {
action = "next";
pagination(action);
})
//Previous
$("#prev").click(function() {
action = "prev";
pagination(action);
})
#item-wrapper {
width:250px;
margin:30px 0 0 30px;
}
.items li {
font-family:arial;
font-size:13px;
background-color:#ccc;
margin-bottom:1px;
padding:5px;
}
.ctrl-nav {
background-color:#999;
padding:5px;
overflow:hidden;
}
.ctrl-nav a {
font-family:arial;
font-size:13px;
padding:5px 10px;
color:#fff;
}
.ctrl-nav a#prev{
float:left;
}
.ctrl-nav a#next{
float:right;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="filter">
category 1
category 2
</div>
<div id="item-wrapper">
<ul class="items">
<li class="category-1">item 1</li>
<li class="category-1">item 2</li>
<li class="category-1">item 3</li>
<li class="category-1">item 4</li>
<li class="category-1">item 5</li>
<li class="category-1">item 6</li>
<li class="category-2">item 7</li>
<li class="category-2">item 8</li>
<li class="category-2">item 9</li>
<li class="category-2">item 10</li>
<li class="category-2">item 11</li>
<li class="category-2">item 12</li>
<li class="category-1">item 13</li>
<li class="category-1">item 14</li>
<li class="category-2">item 15</li>
</ul>
<div class="ctrl-nav">
PreviousNext
</div>
</div>
Here you have my approach...
CSS:
div.ctrl-nav a {
padding: 5px;
margin-right: 2px;
color: white;
background: black;
}
div.ctrl-nav a.selected {
background: red;
}
JQUERY:
var selCatId = null;
var pageLength = 3;
// Filters.
$('div.filter').on('click','a',function(e) {
e.preventDefault();
// Get the category id from the href attribute.
selCatId = $(this).attr('href').substring(1);
// Create pagination.
var nPages = Math.ceil($('div#item-wrapper ul.items li.'+selCatId).length / pageLength),
pages = [];
// Create and show page numbers.
for (var i=1; i<=nPages; i++)
pages.push(''+i+'');
$('div.ctrl-nav').html(pages.join(''));
// Activate page number selection.
$('div.ctrl-nav a').click(function(e) {
e.preventDefault();
var pageInit = (parseInt($(this).text())-1)*pageLength;
$('div#item-wrapper ul.items li').hide()
.filter('.'+selCatId)
.slice(pageInit,pageInit+pageLength)
.show();
// Mark the active page.
$('div.ctrl-nav a').removeClass('selected').filter(this).addClass('selected');
});
// Show first page of the selected category.
$('div.ctrl-nav a:first').trigger('click');
});
// Show 'Category 1' when page loads.
$('div.filter a:first').trigger('click');
... and a working file... https://fiddle.jshell.net/rigobauer/zpdk9e6q/
NOTE: When you select a new category, it goes to the first page of that category.
I hope it helps

jquery dynamic filter list

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>

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;
}

Categories