I want to highlight the active page on the side bar menu.
I am using Bootstrap (AdminLTE).
I have tried a number of javascript ways to no avail. Kindly anyone help out. Below is the side bar menu.
<ul class="sidebar-menu" >
<li class=""><i class="fa fa-dashboard"></i> <span>Dashboard</span> </li>
<br>
<li class="treeview">
<i class="fa fa-cogs"></i> <span> Account Configuarion</span> <i class="fa fa-angle-left pull-right"></i>
<ul class="treeview-menu">
<li class="treeview">
<i class="fa fa-mobile fa-lg"></i> <span>M-PESA C2B</span> <i class="fa fa-angle-left pull-right"></i>
<ul class="treeview-menu">
<li class=""><i class="fa fa-arrow-circle-right"></i>C2B Settings</li>
<li class=""><i class="fa fa-arrow-circle-right"></i> Online CheckOut</li>
<li class=""><i class="fa fa-arrow-circle-right"></i> STK Push</li>
</ul>
</li>
<li class="treeview">
<i class="fa fa-mobile fa-lg"></i> <span>M-PESA B2C</span> <i class="fa fa-angle-left pull-right"></i>
<ul class="treeview-menu">
<li><i class="fa fa-arrow-circle-right"></i> B2C Settings</li>
</ul>
</li>
<li class="treeview">
<i class="fa fa-send"></i> <span>SMS</span> <i class="fa fa-angle-left pull-right"></i>
<ul class="treeview-menu">
<li class=""><i class="fa fa-arrow-circle-right"></i>SMS Settings</li>
<li class=""><i class="fa fa-arrow-circle-right"></i>Subscription SMS Settings</li>
</ul>
</li>
</ul>
</li>
<li class="treeview ">
<i class="fa fa-cogs"></i> <span>Account Info</span> <i class="fa fa-angle-left pull-right"></i>
<ul class="treeview-menu">
<li class=""><i class="fa fa-arrow-circle-right"></i> Buy Units</li>
<li class=""><i class="fa fa-arrow-circle-right"></i>Account Details</li>
<li class=""><i class="fa fa-arrow-circle-right"></i>Account Users</li>
</ul>
</li>
</ul>
I tried with this javascript code but ends up opening all the dropdowns. All the same, it does highlight the current item. But I would want the other items remain closed and only active remains open.
<script>
$(document).ready(function() {
var url = window.location;
var element = $('ul.sidebar-menu a').filter(function() {
return this.href == url || url.href.indexOf(this.href) == 0; }).parent().addClass('active');
if (element.is('li')) {
element.addClass('active').parent().parent('li').addClass('active')
}
});
</script>
/** Try this ** >
for sidebar and treeview menu in adminLTE, it will add active when clicked and remove any previous active class
/** to add active class and remove previously clicked menu */
var url = window.location;
// for sidebar menu but not for treeview submenu
$('ul.sidebar-menu a').filter(function() {
return this.href == url;
}).parent().siblings().removeClass('active').end().addClass('active');
// for treeview which is like a submenu
$('ul.treeview-menu a').filter(function() {
return this.href == url;
}).parentsUntil(".sidebar-menu > .treeview-menu").siblings().removeClass('active menu-open').end().addClass('active menu-open');
Finally I figured it out!
I included the script below;
<script>
/** add active class and stay opened when selected */
var url = window.location;
// for sidebar menu entirely but not cover treeview
$('ul.sidebar-menu a').filter(function() {
return this.href == url;
}).parent().addClass('active');
// for treeview
$('ul.treeview-menu a').filter(function() {
return this.href == url;
}).parentsUntil(".sidebar-menu > .treeview-menu").addClass('active');
</script>
Then included on all <ul class="treeview-menu"> I believe this prevented the lists from opening unless clicked.
This ultimately sorted everything.
Try this:v2.3.0
var url = window.location;
// for sidebar menu entirely but not cover treeview
$('ul.sidebar-menu a').filter(function() {
return this.href == url;
}).parent().addClass('active');
// for treeview
$('ul.treeview-menu a').filter(function() {
return this.href == url;
}).parentsUntil(".sidebar-menu > .treeview-menu").addClass('active');
Please check below-mentioned solution :
<script type="text/javascript">
$(document).ready(function(){
var url = window.location.href.substr(window.location.href.lastIndexOf("/") + 1);
$('.treeview-menu li').removeClass('active');
$('[href$="'+url+'"]').parent().addClass("active");
$('.treeview').removeClass('menu-open active');
$('[href$="'+url+'"]').closest('li.treeview').addClass("menu-open active");
});
</script>
NOTE: This code for new AdminLTE 3 dev with bootstrap 4
var url = window.location;
const allLinks = document.querySelectorAll('.nav-item a');
const currentLink = [...allLinks].filter(e => {
return e.href == url;
});
currentLink[0].classList.add("active")
currentLink[0].closest(".nav-treeview").style.display="block";
currentLink[0].closest(".has-treeview").classList.add("active");
I don't want this question to be polluted by another answer but none of them worked for AdminLTE-3.0.1.So I created an updated solution.Here is
const url = window.location;
/*remove all active and menu open classes(collapse)*/
$('ul.nav-sidebar a').removeClass('active').parent().siblings().removeClass('menu-open');
/*find active element add active class ,if it is inside treeview element, expand its elements and select treeview*/
$('ul.nav-sidebar a').filter(function () {
return this.href == url;
}).addClass('active').closest(".has-treeview").addClass('menu-open').find("> a").addClass('active');
If anyone need to fix this on Admin LTE 4 this is working:
<script>
/** add active class and stay opened when selected */
var url = window.location;
// for sidebar menu entirely but not cover treeview
$('ul.nav-sidebar a').filter(function() {
return this.href == url;
}).addClass('active');
// for treeview
$('ul.nav-treeview a').filter(function() {
return this.href == url;
}).parentsUntil(".nav-sidebar > .nav-treeview").addClass('menu-open').prev('a').addClass('active');
</script>
This a follow up to GMK Hussain answer for AdminLTE 3. I ran into the null issue and undefined in his code(undefined because I have some pages that are not in nav links at all). I would get jS console errors. Here is what I am using:
$(document).ready(function () {
var url = window.location;
const allLinks = document.querySelectorAll('.nav-item a');
const currentLink = [...allLinks].filter(e => {
return e.href == url;
});
//fix for "cannot read property 'style' of null" on windows.location urls not in the nav, indefined on edit/create pages with id number
if (typeof currentLink[0] !== 'undefined') {
if (currentLink[0].closest(".nav-treeview") !== null) {
currentLink[0].classList.add("active");
currentLink[0].closest(".nav-treeview").style.display = 'block';
currentLink[0].closest(".has-treeview").classList.add("active");
currentLink[0].closest(".has-treeview").classList.add("menu-open");
}
}
});
I also added: currentLink[0].closest(".has-treeview").classList.add("menu-open");
This will toggle the collapsing of the higher level item possible, without it you had to click the higher level nav twice before it would toggle close.
Adminlte4
$(document).ready(function(){
const url = window.location;
$('ul.nav-sidebar a').filter(function() {
return this.href == url;
}).parent().addClass('active');
$('ul.nav-treeview a').filter(function() {
return this.href == url;
}).parentsUntil(".sidebar-menu > .nav-treeview").addClass('menu-open');
$('ul.nav-treeview a').filter(function() {
return this.href == url;
}).addClass('active');
$('li.has-treeview a').filter(function() {
return this.href == url;
}).addClass('active');
$('ul.nav-treeview a').filter(function() {
return this.href == url;
}).parentsUntil(".sidebar-menu > .nav-treeview").children(0).addClass('active');
});
Solution without JQuery :
JS Code :
function isActiveElement (route, device, domain, classAsked) {
var pathName = window.location.pathname;
var routeName = pathName.split("/")[1];
var deviceName = pathName.split("/")[2];
var domainName = pathName.split("/")[3];
var className = ""
if(route !== "" && routeName === route) {
className = classAsked;
}
if(domain !== "" && domainName !== domain) {
className = "";
}
if(device !== "" && deviceName !== device) {
className = "";
}
return className;
}
HTML Code :
<li className={"nav-item has-treeview " + isActiveElement(route, "", domain, "menu-open")}>
<a href="#" className={"nav-link " + isActiveElement(route, "", domain, "active")}>
I'm using this code to add active class depending of the page.
This is working ok except for multi level submenus any clue how to fix this,
add active class and stay opened when selected
var url = window.location;
// for sidebar menu entirely but not cover treeview
$('ul.sidebar-menu a').filter(function() {
return this.href == url;
}).parent().addClass('active');
// for treeview
$('ul.treeview-menu a').filter(function() {
return this.href == url;
}).closest('.treeview').addClass('active');
**HTML**
<li class="treeview">
<a href="#">
<i class="fa fa-gears"></i>
<span>Settings</span>
<i class="fa fa-angle-left pull-right"></i>
</a>
<ul class="treeview-menu">
<li>
<a href="#">
<i class="fa fa-bars"></i>
Specials Settings
</a>
<ul class="treeview-menu">
<li>Setting 1</li>
</ul>
</li>
</ul>
</li>
Related
I'm just trying to work on new slider menu but I've a problem with Jquery.
I've a link. When I click on I use .css('left', -230) and all is okay but when i want to reverse by another clicked link like .css('left', 0) nothing happen.
I show you some code :
// The open part "target.width()" = 230
$('.nav-item').on('click', function () {
if( 0 < $(this).find('.navbar-nav__sub').length ) {
var target = $('.navbar-nav');
target.css('left', -target.width());
}
});
// The close part
$('.navbar-nav__sub .go-back').on('click', function () {
console.log('HERE');
var target = $('.navbar-nav');
console.log(target);
console.log(target.css('left'));
target.css('left', 0);
console.log(target.css('left'));
console.log('END');
});
A strange thing in this problem is that I've this in my console :
HERE
Object { 0: ul.navbar-nav.flex-column, length: 1, prevObject: […] }
-230px
0px
END
It seem that the code work well but in my page the left attribute is always to -230px.
Someone have an idea ?
Thank you.
PS: As asked the JSfiddle who reproduce my problem
https://jsfiddle.net/w7Lknsxg/
If you click on "Menu01" Color turn to red and when you click on "<=" in submenu you have the execution in the console but the color don't change.
You can see the class navbar-nav get new class "toto" but don't lost when I try to remove it in the second case.
Because the .go-back is nested within the .nav-item you are firing both event listeners due to event bubbling. You can stop this with event.stopPropagation(); from within the listener placed on the child item. (or be more specific in what you target as not to include subelements)
var ftl = window.ftl || {};
ftl.navbar = {
config: {
targetName: '.nav',
target: null,
},
init: function init() {
this.config.target = $(this.config.targetName);
$('.navbar-toggle').on('click', function () { ftl.navbar.toggle(); });
$('.nav-item').on('click', function () {
if( !ftl.navbar.config.target.hasClass('open') ) {
ftl.navbar.open();
}
// test la présence d'un sous menu
if( 0 < $(this).find('.navbar-nav__sub').length ) {
var target = $('.navbar-nav');
target.addClass('toto');
target.css('color', 'red');
}
});
$('.navbar-nav__sub .go-back').on('click', function (event) {
event.stopPropagation();
console.log('HERE');
var target = $('.navbar-nav');
console.log(target);
console.log(target.hasClass('toto'));
target.removeClass('toto');
target.css('color', "green");
console.log('END');
})
},
open: function open() {
this.config.target.addClass('open').one('transitionend', function () {
ftl.navbar.config.target.addClass('opened');
});
},
close: function close() {
this.config.target.removeClass('opened')
.removeClass('open');
},
toggle: function toggle() {
if( this.config.target.hasClass('open') ) {
this.close();
} else {
this.open();
}
}
}
$(document).ready(function() {
ftl.navbar.init();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav class="nav">
<nav class="navbar" role="navigation">
<div class="container-nav flex-column">
<div class="navbar__header">
<a href="#" class="no-style">
<i class="fa fa-comment-o fa-2x navbar__icon" aria-hidden="true"></i>
<span class="navbar__text"><strong class="text-primary">web</strong>tutu</span>
</a>
</div>
<div class="navbar__divider"></div>
<ul class="navbar-nav flex-column">
<li id="nav-item--one" class="nav-item">
<a href="#nav-item--one">
<i class="fa fa-user-circle-o navbar__icon" aria-hidden="true"></i>
<span class="navbar__text">Menu01</span>
</a>
<ul class="navbar-nav__sub">
<li>link 01</li>
<li>link 02</li>
<li><a class="go-back" href="#"> <= </a></li>
</ul>
</li>
<li id="nav-item--two" class="nav-item">
<a href="#nav-item--two">
<i class="fa fa-user-circle-o navbar__icon" aria-hidden="true"></i>
<span class="navbar__text">Menu02</span>
</a>
</li>
<li id="nav-item--three" class="nav-item">
<a href="#nav-item--three">
<i class="fa fa-user-circle-o navbar__icon" aria-hidden="true"></i>
<span class="navbar__text">Menu03</span>
</a>
</li>
<li class="mt-auto">
<i class="fa fa-angle-double-right fa-2x navbar-toggle" aria-hidden="true"></i>
</li>
</ul>
</div>
</nav>
</nav>
I have an issue with my child menus.When I click a child menu it becomes active after http request but I want it to remain expanded after http request(page refresh).Menu structure is below.
<ul class="sidebar-navigation>
#foreach($parent as $parent)
<li>{{$parent->name}}
<ul>
#foreach($child as $child)
#if(isset($_GET['name']) && $_GET['name'] == $child->name)
<li class="active">
#endif
{{$child>name)}}
</li>
#endforeach
</ul>
</li>
#endforeach
</ul>
Here is an idea, and it's what i do to acheieve this effects. i use AdminLTE, you should base this code to change your code, Basic idea is judge current route if route need open sidebar then give a class 'active'
to html tag.
Html:
<div class="main-sidebar">
<div class="sidebar">
<ul class="sidebar-menu">
<li class="treeview {{ sidebar_open(['admin.roles.*']) }}">
<a href="#">
<i class="fa fa-user-secret"></i>
<span>角色管理</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li><i class="fa fa-circle-o"></i>角色列表</li>
<li><i class="fa fa-circle-o"></i>新建角色</li>
</ul>
</li>
</ul>
define a helper functions:
<?php
if (!function_exists('sidebar_open')) {
function sidebar_open($routes = []) {
$currRoute = Route::currentRouteName();
$open = false;
foreach ($routes as $route) {
if (str_contains($route, '*')) {
if (str_contains($currRoute, substr($route, '-1'))) {
$open = true;
break;
}
} else {
if ($currRoute === $route) {
$open = true;
break;
}
}
}
return $open ? 'active' : '';
}
}
I have the basis of my menu working, where when I click a menu element, it opens (similar to JQuery accordion), and when I click on another element in the menu, the previously opened menu closes and the newly clicked on opens. Here's what it looks like:
Now, I'm trying to implement functionality to close the currently opened menu if it is clicked again. I'm using the slideUp(); method, but having a hard time figuring out where to put the additional code for the 2nd click on the same element.
Here's what I have:
navigation.html.erb
<!-- menu links -->
<div id="sidebar-menu" class="main_menu_side hidden-print main_menu">
<div class="menu_section">
<h3>General</h3>
<ul class="nav side-menu">
<li><a><i class="fa fa-home"></i> Home <span class="fa fa-chevron-down"></span></a>
<ul class="nav child_menu" style="display: none">
<li>Dashboard
</li>
</ul>
</li>
<li><a><i class="fa fa-edit"></i> Forms <span class="fa fa-chevron-down"></span></a>
<ul class="nav child_menu" style="display: none">
<li>General Elements
</li>
</ul>
</li>
<li><a><i class="fa fa-bar-chart-o"></i> Data Presentation <span class="fa fa-chevron-down"></span></a>
<ul class="nav child_menu" style="display: none">
<li>Chart JS
</li>
</ul>
</li>
</ul>
</div>
</div>
custom.js
var URL = window.location,
$BODY = $('body'),
$MENU_TOGGLE = $('#menu_toggle'),
$SIDEBAR_MENU = $('#sidebar-menu'),
$SIDEBAR_FOOTER = $('.sidebar-footer'),
$LEFT_COL = $('.left_col'),
$RIGHT_COL = $('.right_col'),
$NAV_MENU = $('.nav_menu'),
$FOOTER = $('footer');
var setContentHeight = function () {
// reset height
$RIGHT_COL.css('min-height', $(window).height());
var bodyHeight = $BODY.height(),
leftColHeight = $LEFT_COL.eq(1).height() + $SIDEBAR_FOOTER.height(),
contentHeight = bodyHeight < leftColHeight ? leftColHeight : bodyHeight;
// normalize content
contentHeight -= $NAV_MENU.height() + $FOOTER.height();
$RIGHT_COL.css('min-height', contentHeight);
};
$SIDEBAR_MENU.find('a').on('click', function(ev) {
var $li = $(this).parent();
if ($li.hasClass('.active')) {
$li.removeClass('active');
$('ul:first', $li).slideUp(function(){
setContentHeight();
});
} else {
$li.addClass('active');
$SIDEBAR_MENU.find('.side-menu li').not($li).removeClass('active');
$SIDEBAR_MENU.find('.side-menu li').not($li).find('.child_menu').removeClass('active').slideUp();
$('ul:first', $li).slideDown(function(){
setContentHeight();
});
}
});
Change if ($li.hasClass('.active')) to if ($li.hasClass('active')) and that should resolve the issue. Check this fiddle. I have created an empty setContentHeight function to make it work.
I'm working on a project and stuck on the tabs. No matter what I do the page scrolling down when I click a tab. This is my HTML:
<ul class="list">
<li class="tab1 active">
<i class="fa fa-external-link"></i>
Quick Reports
</li>
<li class="tab1">
<i class="fa fa-star-o"></i>
My Folders
</li>
<li class="tab1">
<i class="fa fa-folder-open-o"></i>
My Team Folders
</li>
<li class="tab1">
<i class="fa fa-files-o"></i>
Public Folders
</li>
</ul>
var open_tab = function() {
$('.tab1').each(function (i, tab) {
UTILS.addEvent(tab, 'click', function() {
$('.list li.active').removeClass('active');
$(this).addClass('active');
$('.active-panel').removeClass('active-panel');
var target_panel_selector = $(this).find('a').attr('href');
$(target_panel_selector).addClass('active-panel');
window.location.hash = target_panel_selector ;
});
});
};
And the style of .active-panel is display: block. I tried to use:
e.preventDefault();
or
tab.find('a').on('click', function(e){
alert("finally!!");
e.preventDefault();
});
and other stuff I found on the web but nope, not working.
<ul class="list">
<li class="tab1 active">
<i class="fa fa-external-link"></i>
<a data-href="#quick-reports" class="tab" href="javascript:void(0)">Quick Reports</a>
</li>
<li class="tab1">
<i class="fa fa-star-o"></i>
<a data-href="#my-folders" class="tab" href="javascript:void(0)">My Folders</a>
</li>
<li class="tab1">
<i class="fa fa-folder-open-o"></i>
<a data-href="#my-team-folders" class="tab" href="javascript:void(0)">My Team Folders</a>
</li>
<li class="tab1">
<i class="fa fa-files-o"></i>
<a data-href="#public-folders" class="tab" href="javascript:void(0)">Public Folders</a>
</li>
</ul>
<script>
function maketabActive($strElement)
{
$('.list li.active').removeClass('active');
$strElement.addClass('active');
$('.active-panel').removeClass('active-panel');
var target_panel_selector = $strElement.find('a').data('href');
$(target_panel_selector).addClass('active-panel');
// Save selected tab index in session stroage.So after page refresh active tab will be maintained
sessionStorage.setItem('selected-tab', $strElement.index());
}
$(document).ready(function () {
// Check if selected tab is stored in session stroage
if (sessionStorage.getItem('selected-tab'))
{
//Make tab active based on index got from session stroage
maketabActive($(".tab1:eq(" + sessionStorage.getItem('selected-tab') + ")"));
}
});
var open_tab = function () {
$('.tab1').each(function (i, tab) {
UTILS.addEvent(tab, 'click', function () {
maketabActive($(this));
});
});
};
</script>
I think that it's scrolling when you are setting the hash here
window.location.hash = target_panel_selector ;
Take a look at: https://stackoverflow.com/a/14690177/5612557
UPDATE
Try to add a return false into the click event and as suggest Diego change the hash method (but work only in a newer browser) like this:
var open_tab = function() {
$('.tab1').each(function (i, tab) {
UTILS.addEvent(tab, 'click', function() {
$('.list li.active').removeClass('active');
$(this).addClass('active');
$('.active-panel').removeClass('active-panel');
var target_panel_selector = $(this).find('a').attr('href');
$(target_panel_selector).addClass('active-panel');
//window.location.hash = target_panel_selector ;
if(history.pushState) {
history.pushState(null, null, target_panel_selector);
} else {
window.location.hash = target_panel_selector;
}
return false; // <-- add this line
});
});
};
You may try
event.stopPropagation();
My HTML code looks like this:
<div id="sidebar-menu" class="main_menu_side hidden-print main_menu">
<div class="menu_section">
<ul class="nav side-menu">
<li>
<a>
<i class="fa fa-home"></i>home
<span class="fa fa-chevron-down"></span>
</a>
<ul class="nav child_menu" style="display: none">
<li>
Dashboard
</li>
<li>
dashbord2
</li>
</ul>
</li>
<li>
<a>
<i class="fa fa-edit"></i>form
<span class="fa fa-chevron-down"></span>
</a>
<ul class="nav child_menu" style="display: none">
<li>
general form
</li>
<li>
form validation
</li>
</ul>
</li>
</ul>
</div>
</div>
to add/remove class based on current url, i am using this:
$(function () {
var url = window.location.href;
$('#sidebar-menu a[href="' + url + '"]').parent('li').addClass('current-page');
$('#sidebar-menu a').filter(function () {
return this.href == url;
}).parent('li').addClass('current-page').parent('ul').slideDown().parent().addClass('active');
});
It works, but when i click this link
dashbord2
the class="current-page" doesn't change to current path url
How i fix this?
Your issue arises from the page not being reloaded when you click on the link with hash in it, while your code only executes on page load, or dom ready to be exact. The solution is to whether use window's hashchange event (not supported in < IE8) or, like #sirrocco mentioned, use click event with setTimeout to detect the change of hash:
function setCurrentMenuPage() {
var url = window.location.href;
var anchors = $('#sidebar-menu a');
anchors.parent('li').removeClass('current-page');
anchors.filter(function () {
return this.href == url;
}).parent('li').addClass('current-page').parent('ul').slideDown().parent().addClass('active');
}
$(function () {
setCurrentMenuPage();
$('#sidebar-menu a').on('click', function (e) {
if ($(this).attr('href').indexOf("#") >= 0) {
setTimeout(function () {
setCurrentMenuPage();
}, 100);
}
});
});
Hope that helps.