Setting <li> class as active using Javascript, not working? - javascript

I have several javascript generated sub menus, which are displayed when a certain word is found in the current url.
I need to set a li tag to li class="active" so that the user can see which submenu page they are currently browsing.
I've found a variety of codes which seem to be relevant, but I can't seem to make any work! The below works perfectly to generate the sub menus though :)
If it helps I'm using the twitter bootsrap for design purposes, for some reason the css file has alot of arrows inserted, eg. .tabs > li
I don't really understand what the > has been inserted for, but could that be causing some kind of a problem perhaps?
Any help much appreciated!
var currenturl = location.pathname
if (currenturl.search(/welcome/i) >= 0)
{
document.write(<ul class="tabs">
<li>Home</li>
<li>Contacts</li>
<li><a href="user_manual.php" User Manual</a></li>
<li>Support & Help</li>
<li>Logout</li>
</ul>);
}
Ok Here's an update!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Wow thanks very much for the reply. I have added the code inside a javascript declaration before the closing body tag as mentioned, though on the welcome.php page I do not see any sub menu having been generated.
In response to the other comment, what I would like to achieve is generating a sub menu based upon the current pages URL.
If the URL contains "support" I would like it to load a certain menu, if "sales" I would like it to load another.
An example sub menu, the one I want to appear when "sales" is detected in the URL is as follows:
<ul class="tabs">
<li>Contacts</li>
<li><a href="sales-user_manual.php" User Manual</a></li>
<li>Support & Help</li>
<li>Something Else</li>
</ul>
To make the current sub menu active I have to further set an li tag active as such:
<li class="active">
This means I will need another piece of code to detect the end of the URL string eg. if the current page open is sales-contact_us.php then the li tag for that menu item is set active.
Thanks!

You should definitely not use document.write to append elements to the document. Use DOM methods instead, eg
var menu = [
{ "label": "Home", "href": "welcome.php" },
{ "label": "Contacts", "href": "contact_us.php" }
// etc
];
var list = document.createElement("ul");
list.setAttribute("class", "tabs");
for (var i = 0; i < menu.length; i++) {
var label = menu[i].label;
var href = menu[i].href;
var item = document.createElement("li");
var anchor = document.createElement("a");
anchor.appendChild(document.createTextNode(label));
anchor.setAttribute("href", href);
if (href == currentUrl) {
item.setAttribute("class", "active");
}
item.appendChild(anchor);
list.appendChild(item);
}
document.body.appendChild(list); // you may want to append the list to another container
Place the above in a script block at the end of your document (right before the closing </body> tag) to ensure the document has loaded before attempting to manipulate it.

Related

Highlight the current menu item?

So basically I'm trying to give a class "current" to highlight the menu item for the current page.
I've tried a couple of snippets I've seen on this website but most of them didn't work. This code is almost working for me, but the problem is although the current menu item is properly highlighted, Home button is also highlighted no matter which page I'm viewing. So like if I'm viewing "Archive" page, both Archive and Home are highlighted.
I'm using Wordpress to build the website by the way and I'm aware that Wordpress supports this effect but I'd like to achieve this without it.
HTML
<ul class="navigation">
<li>Home</li>
<li>Archive</li>
<li>About</li>
</ul>
JS
jQuery(function($) {
$('.navigation li a').each(function() {
var target = $(this).attr('href');
if(location.href.match(target)) {
$(this).addClass('current');
} else {
$(this).removeClass('current');
}
});
});
I'm not really familiar with javascript so there might be some errors.
Thank you for reading this, and have a great new year.
The suggestion of wp_nav_menu is the correct way in WordPress, but if you're just looking for a quick solution and the menu won't change that often, you can get by with a check inside of each list item.
<ul class="navigation">
<li>Home</li>
<li>Archive</li>
<li>About</li>
</ul>
This makes use of WordPress' "Conditional Tags" which effectively come back as "true" or "false" for a given page. Note that the second link checks multiple blog/post conditions (assuming that that is for the blog).
I'm not sure this is help you or not.
If you are using wordpress you can use this for your menu:
<?php
wp_nav_menu(array(
'theme_location' => 'header',
'menu_class' => 'navbar-nav px-0',
'depth' => 2,
'container' => false,
));
?>
and wordpress automatically add aria-current="page" to your 'nav-link' when you landing on current page.
then you can add css to attribute current page like this
ul.navbar-nav [aria-current]:not([aria-current="false"])
Also if you have 'sub-menu' wordpress add '.sub-menu' class to ul child and you can add css like this for 'sub-menu'.
ul.navbar-nav li ul.sub-menu [aria-current]:not([aria-current="false"])
this is my last website you can check it: http://kimiaroz.com/
You can use simple filter
add_filter('nav_menu_link_attributes', 'add_current_class_to_link', 10, 4);
function add_current_class_to_link($atts, $item, $args, $depth)
{
$atts['class'] = $item->current ? 'current' : '';
return $atts;
}

How to dynamically get the dynamically created ID in a li

I've been trying to learn js (and a tad of jquery) and I have run into two difficulties when trying to find a way to combine solutions that I find.
Just a little warning that this code is a mix of a few tutorials that I have recently done. I am very new to js.
So I start with a basic html with a few li.
<body>
<ol id="liste">
<li class="active">
</li>
<li>
</li>
<li>
</li>
</ol>
<div id="main_ima">
</div>
<script src="js/main.js"></script>
</body>
I want to create ids for each "li" so in my main.js I add this:
var idVar = $("#liste").find("li").each(function(index){
$(this).attr("id","num-li-"+index);
});
This works great so far. Everytime I add a new li, it gets a new id. I also put it into a var because I will need to use it later.
In th console, If I type idVar, it gives me the whole list of li. If I type idVar[3]. it only gives me the li associated to the [3]. Perfect.
Now I want to get something to appear when one of the li is clicked. For example, I will use the [3]. So I add this to my main.js
var imaContainer = document.getElementById('main_ima')
var listed = document.getElementById('liste');
idVar[3].addEventListener("click", appar);
function appar(){
$(idVar[3]).addClass("active").siblings().removeClass("active");
var imaSel = new XMLHttpRequest();
imaSel.open('GET', 'https://domain.link.to.file.json');
imaSel.onload = function() {
var imaLo = JSON.parse(imaSel.responseText);
renderHTML(imaLo);
};
imaSel.send();
};
function renderHTML(data) {
var htmlS = "";
for (i = 0; i < data.length; i++) {
htmlS += "<p>" + data[i].name + " is a " + data[i].species + ".</p>";
}
imaContainer.insertAdjacentHTML('beforeend', htmlS);
}
Just a side note, I added the add/remove "active" class for CSS.
So when I click the li[3], it works almost as expected. The only thing is when I reclick [3] it produces the result a 2nd time. And again, if I click it a 3rd time, it produces the result a 3rd time, without remove the past results. (which is not totally what I want. Just the 1st result would be better.)
But that is not the main problem I am facing.
I would like the [number] to be dynamically detected, based on the id of the clicked li. I could, in a very ugly way, copy and past this code for every [number] I have. and it would work. But then, what if I want to add more li elements, I would need to add more copy and paste of the above code, giving me possibly huge files for nothing. This is surely not the best way, although it would work.
I'm sure this can be done dynamically.. but that is mostly why I am here. :)
Afterwards, once the dynamic has been added to the clicked li, I would also like the link to be changed dynamically based on the li id. For example, instead of :
imaSel.open('GET', 'https://domain.link.to.file.json');
something like:
imaSel.open('GET', "https://domain.link.to.file" + var +".json");
the var being equal to the [3] number of the clicked li.
In this case, when I try to add a var with a for loop, I always get the "var = max.length" instead of the "var = [id of clicked item]".
So there you have it. Do you need more details?
This is my first JS and/or Jquery try. I've been playing with it for a few days but when I search for answers, when I implement the "solutions" it alwas gives me some new problem. So I am showing you the code that is the closest, IMO, to what I am looking for.
Hopefully, I am not too far away of somehting that works and is not as big as my solutions. :)
Thanks for your time and all help is appreciated.
Here are some suggestions:
You don't need to assign id attributes to your li. You actually never need that id. This will work just as well (note also the > in the selector which makes the find call unnecessary):
var $li = $("#liste > li");
Already now you can address each of the li as $li[3], although that is not the "best practise". Better is $li.get(3). I also like the convention to start the variable with $ when it is the result of a jQuery selection. It gives a clue that you can apply jQuery methods to it.
You don't need to assign a click handler to each li separately. With jQuery on (instead of the native addEventListener) you can assign one event handler for all of them at once.
$li.on('click', apar)
The callback you define for on will have this set to the particular li element that has been clicked, so you can do:
$(this).addClass("active").siblings().removeClass("active");
... without any array lookup.
jQuery offers easy functions for several types of HTTP requests, so you don't need to use XMLHttpRequest. In fact, there is one specifically for getting JSON, so you don't even have to parse the response:
$.getJSON('https://domain.link.to.file.json', renderHTML);
The jQuery index() method can give you the sequence number of that li:
$.getJSON('https://domain.link.to.file' + $(this).index() + '.json', renderHTML);
To replace the inner HTML of a certain element, the jQuery html method can be used:
$('#main_ima').html(htmlS);
Note also how you don't need the DOM native getElementById method, jQuery can look that up for you with the short $('#main_ima').
Example
Here is a working example with a fake JSON serving server:
$("#liste > li").on('click', apar);
function apar() {
$(this).addClass("active").siblings().removeClass("active");
$.getJSON('https://jsonplaceholder.typicode.com/posts/'
+ (1+$(this).index()), renderHTML);
}
function renderHTML(data) {
// This particular JSON request returns an object with body property
var htmlS = data.body;
$('#main_ima').html(htmlS);
}
// On page load, click on the first `li` to automatically load the data for it
$('#liste > li:first').click();
#liste { width: 40px }
.active { background: yellow }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ol id="liste">
<li class="active">load 1</li>
<li>load 2</li>
<li>load 3</li>
</ol>
<div id="main_ima"></div>
The following answers your main concern, how to dynamically get the ID with jquery:
$('.listen-to-me').click(function() { //Add event listener to class
var elementId = $(this).attr('id'); //Get the 'id' attribute of the element clicked
var idNumber = elementId.substring(elementId.indexOf("-") +1); //Get the index of the "-" in the string, and then cut everything prior
alert(idNumber); //The final result
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li id="test-1" class="listen-to-me">1</li>
<li id="test-2" class="listen-to-me">2</li>
<li id="test-3" class="listen-to-me">3</li>
<li id="test-4" class="listen-to-me">4</li>
<li id="test-5" class="listen-to-me">5</li>
</ul>

How to apply a function to the a tags in only one specific div or class without jquery

I have several menus on one page and want the link that the user clicks in each menu to change colors and remain that color until the user clicks another link in that menu. I have this code:
JavaScript
function bookswitchColor(element, color) {
links = document.getElementsByTagName("a");
for (var i = 0; i < links.length; i++)
links.item(i).style.color = 'red';
element.style.color = "#0E00EB";
}
HTML
<div id="book" class="book">
<ul>
<li>Menu
</li>
<li>Book1
</li>
<li>book2
</li>
</ul>
</div>
Which works except that it changes the a tags on the entire page. This page displays a library of books. When a user clicks on one of the books, I need that book to remain highlighted(color changed). Clicking on a book calls a list of chapters for that book which the user clicks to read that chapter. I need the chapter to remain highlighted(color changed) also without affecting the other menus.
I would like to avoid jQuery.
Just replace this line
links=document.getElementsByTagName("a") ;
with this one:
var links = document.getElementById("book").getElementsByTagName("a");
You can use .getElementsByTagName() from any element node.
var links = document.getElementById('book').getElementsByTagName('a');

highlight in different colors for links in main menu based on current page

How to highlight every link in main menu with a different color based on its current page ?
for example change the contact us link color to red in the main menu when the current page is contact us
and change the about us link color to orange in the main menu when the current page is about us and so on
You can use javascript to do this:
first, retrieve your current url path:
var pathname = window.location.pathname;
for example, return "/contact.html"
then you can use this value to detemine which item to be hilighted:
if(pathname == "/contact.html"){
document.getElementById("contact").addClass("hilighted");
}
and so on.
a:active : when you click on the link and hold it.
a:visited : when the link has already been visited.
If you want the link corresponding to current page to be highlighted, you can define some specific style to the link -
.current {
color: red;
background-color: #000000;
}
Add this new class .current only to the corresponding li (link), either on server-side or on client-side (using javascript/jquery).
With JQuery you could use the .each function to iterate through the linkswith the following code:
$(document).ready(function() {
$("[href]").each(function() {
if (this.href == window.location.href) {
$(this).addClass("current");
}
});
});
Depending on your page structure and used links, you may have to narrow down the selection of links like:
$("nav [href]").each ...
if you are using url parameters, it may be necessary to strip these:
if (this.href.split("?")[0] == window.location.href.split("?")[0]) ...
This way you don't have to edit each page.
source
There are a lot of approaches, it's hard to say which is best without seeing your code.
You could use some Javascript on each page to add or change the class of your links.
For instance on your contact us page use a a script like
var contactLink = document.getElementById("contactUs");
contactLink.addClass("orangeLink");
You can add active class to the menu based on current page.
if you are in contact page then add active class to contact us menu, same for about us page, then do some css for that active class.
for example if you are in contact-us page then :-
<ul>
<li class="home">Home</li>
<li class="contact active">Contact Us</li>
<li class="about">About Us</li>
</ul>
Now do some css for that :-
.contact.active{
color : red;
}
.about.active{
color : orange;
}
It will worked for you.

Converting CSS template to asp.net with masterpages

I bought an css template.
which implements navigation such that.
<li class="current">Services</li>
<li>News</li>
<li>Portfolio</li>
<li>Elements</li>
<li>Contact</li>
It contains navigation tag in every html file and mark the list item class as current for the current page.
Now i am converting this into master page layout.
How can i detect current page and add class to the list item with JavaScript.
Or any other solution to this problem.
This is one simple way to do this (using jQuery):
function syncMenu () {
var url = window.location.href, pageStart, pageEnd, pageName;
pageStart = url.lastIndexOf("/") + 1;
pageEnd = url.lastIndexOf(".");
pageName = url.substring(pageStart, pageEnd);
$('#Menu').find('li').removeClass('selected');
$('#Menu').find('a[href^="' + pageName + '"]').parent().addClass('current');
}
Call this function as the first thing when your page loads i.e. first thing in document.ready.
The idea is that you have the name of the page as the anchor href. We retrieve the page name from the current url and use that to search the a in all lis which contains that page name as its href. Add a class (current in your case) to that li.

Categories