Perform jQuery action when clicked again - javascript

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.

Related

Jquery, can't update attribute previously created

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>

Pin items from navigation to a separate sidebar (bookmarks)

I'm creating something many would call a bookmark bar, but within the website itself. Basically I have a regular Bootstrap navbar with few menu items that have a "thumb-tack" on them. By pressing the thumb-tack, user can pin that menu item for quick access to a sidebar I've created.
Now before this explanation goes way too messy, here is my current code, which is partially working, but on the other hand it is not.
JSFiddle
HTML
<nav id="oa-navbar" class="navbar navbar-default">
<div class="container-fluid">
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active">
<i class="fa fa-area-chart" aria-hidden="true"></i> Dashboard
</li>
<li>
<i class="fa fa-pencil-square-o" aria-hidden="true"></i> Edit content
</li>
<!-- PINNABLE MENU ITEM!! -->
<li class="pinnable">
<i class="fa fa-picture-o" aria-hidden="true"></i> Media
</li>
</ul>
</div>
</div>
</nav>
<!-- The "Quick-Access" navbar -->
<div id="oa-toolbar">
<div class="container-fluid">
<div id="oa-toolbarbtn" class="oa-btn btn btn-default">
<i class="fa fa-bars" aria-hidden="true"></i> Quick-Access
</div>
<div id="oa-toolbar-pinned">
</div>
</div>
</div>
JS
// Adding the "pinicon" to the pinnable link
$.each($("#oa-navbar li"), function () {
if ($(this).hasClass("pinnable")) {
var pinicon = '<a class="pin-it"><i class="fa fa-thumb-tack" aria-hidden="true"></i></a>';
$(this).find("a").append(pinicon);
}
});
// Pinning the link itself
$("#oa-navbar li .pin-it").click(function () {
var pinMenu = $("#oa-toolbar-pinned");
var nl_content = $(this).parent().html();
var nl = $("<li class='pinnedItem'>"+ nl_content +"</li>");
$(pinMenu).removeClass("active");
if (!$(this).parent().hasClass("pinned")){
$(nl).appendTo(pinMenu);
$(pinMenu).addClass("active");
}
$(this).parent().toggleClass("pinned");
});
The way it works now is that it does add the menu item to the quick-access menu, but it does not take the <a> tags, just what's inside of them.
The other issue is that when I press the thumb-tack on the navigation bar again, it does not remove the pinned item from the quick-access menu. There's got to be an easy way to do this, but I've taken the long road it seems.
Any advice will be more than welcome!
Try this example, actually you were close, I have just reversed your code
$("#oa-toolbar-pinned").on('click','.pinnedItem',function () {
var navBar = $("#oa-navbar ul li"); // find navbar
var content = $(this).find("a").html();
var appendCont = "<li class='pinnable'> <a class='pin-it' href='#'>" + content + "</a></li>"; // take content and surround with li
$(appendCont).appendTo(navBar.parent()); // append to navbar
$(this).remove(); // remove from pinned list
});
Edit 1:
Changed click event to delegate, because there was a problem that newly appended a tags don't fire click event, solved with this,
$(document).on('click', '#oa-navbar li .pin-it' ,function() {}
Hope helps,

Add/Remove class based on active URL

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.

jQuery: how to select the exact element of the same class?

Not sure I've formulated my question well, hope the details will cover the issues.
So, I'm building an "artificial" full-height slide-like submenu, and I have an empty container there:
<section class="masking_sublevel">
</section>
Further, I have a bunch of ul elements in my HTML that are hidden by default in their containing section:
I'm updating the HTML part with a more complete piece:
<div id="sldbr_overlay" class="newully">
<section class="masking_sublevel">
</section>
<ul class="sidebar_bumenu">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
Beauty <i class="fa fa-chevron-right bu_chevright"></i>
<i class="fa fa-chevron-down bu_chevdown"></i>
</a>
<section class="hidden_ul">
<ul>
<li>Aerobics</li>
<li>Pilates</li>
<li>Yoga</li>
<li>Massage</li>
<li>Peeling</li>
<li>Bikini Area Sugaring</li>
<li>Piercing</li>
<li>Tattoo</li>
<li>Shaping</li>
<li>Sauna</li>
<li>Mud SPA</li>
<li>Needle Therapy</li>
<li>Shaping</li>
<li>Leech Therapy</li>
<li>Thai Massage</li>
<li>Wushu</li>
</ul>
</section>
</li>
<li>Clothing</li>
<li>Computers</li>
<li>Construction</li>
<li>Entertainment</li>
<li>Financial</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
Food <i class="fa fa-chevron-right bu_chevright"></i>
<i class="fa fa-chevron-down bu_chevdown"></i>
</a>
<ul class="hidden_ul">
<li>Pizza</li>
<li>Cheboorackee</li>
<li>Khash</li>
<li>Pork</li>
<li>Hamburgers</li>
<li>Greek Salad</li>
<li>BBQ</li>
<li>Tortillas</li>
<li>Spaghetti</li>
<li>Pasta</li>
<li>Ice Cream</li>
<li>Jelly Sugar</li>
<li>Lolly Pop</li>
<li>Cupcakes</li>
</ul>
</li>
<li>Health</li>
<li>Kids</li>
<li>Services</li>
<li>Travel</li>
<li>Tourism</li>
</ul>
<div class="pzik">
<a href="javascript:void(0);" data-toggle=".sidebar_wrapper" id="sidebar-toggle_abs">
<img src="svg/filter.svg" class="filter_icon hvr-wobble-bottom">
</a>
<a href="javascript:void(0);" id="go-2-top" class="gotop_chevron">
<i class="fa fa-chevron-up"></i>
</a>
</div>
</div>
So, what I'm doing is selecting the above mentioned ul and put it within the empty section on a hover event and emptying it on a mouseleave, like this:
$(document).ready(function(){
var dropdownLi = $('li.dropdown');
var maskingSubLvl = $('.masking_sublevel');
var importedUl = $('.masking_sublevel ul');
var hiddenUl = $('.hidden_ul ul');
$(dropdownLi).on('mouseover',function(){
$(hiddenUl).appendTo(maskingSubLvl);
$(maskingSubLvl).css('display','block');
});
$(dropdownLi).on('mouseleave',function(){
$(maskingSubLvl).css('display','none');
$(importedUl).empty();
$(maskingSubLvl).on('mouseenter',function(){
$(this).css('display', 'block');
});
});
});
The problem is that with this piece of code I probably select just the first ul with the class of .hidden_ul', since as I hover on the other items (randomly), it keeps on loading the content of the first list. How can I select the VERY ul element with the same class that I'm currently hovering?
Thanks!
So you want to traverse from the element that has mouseover to the parent ul, which is a child of the grand-parent .hidden_ul
// remove this, it has no context to each drop down
// var hiddenUl = $('.hidden_ul ul');
$(dropdownLi).on('mouseover',function(){
$(this).closest('.hidden_ul').children('ul').appendTo(maskingSubLvl);
// though if there are no child uls in your lis, this will do
$(this).closest('ul').appendTo(maskingSubLvl);
Since your hidden_ul is direct child of .dropdown you need to get it using its parent context as below:
$(dropdownLi).on('mouseover',function(){
var hiddenUl=$(this).find('.hidden_ul')[0];//find the child
$(hiddenUl).appendTo(maskingSubLvl);
$(maskingSubLvl).css('display','block');
});
Update
Instead of appendTo try keeping changing the html of .maskingSubLvl so that no need to remove the content again before appending another. For Ex:
DEMO
$(document).ready(function(){
var dropdownLi = $('li.dropdown');
var maskingSubLvl = $('.masking_sublevel');
var importedUl = $('.masking_sublevel ul');
$(dropdownLi).on('mouseover',function(){
$(maskingSubLvl).css('display','block');
var hiddenUl = $(this).find('.hidden_ul ul').clone(); //clone the content
$(maskingSubLvl).html(hiddenUl);
});
$(dropdownLi).on('mouseleave',function(){
$(maskingSubLvl).css('display','none');
});
$(maskingSubLvl).on('mouseenter',function(){
$(this).css('display', 'block');
});
});

Dropdown submenu selection

My Javascript
var selectmenu = function(index, sub){
$('.main-navigation-menu li:nth-child('+index+')').addclass('active');
}
In my view there are two li tags to select main menu and sub menu; so because of the above JS, it is always selecting a 1st main menu and the 1st sub menu; even when clicking the 2nd sub menu of the 1st main menu... anyone knows how to correct this behavior? Here I wanted to use the 'sub' variable and do something like this:
$('.sub-menu li:nth-child('+index+')').removeClass('active');
$('.sub-menu li:nth-child('+sub+')').addClass('active');
HTML
<ul class="main-navigation-menu ">
#foreach (var menu in mainmenu) {
var sublist = userContext.Menus.Where(m => m.Id == menu.Id);
if (sublist.Count == 0){
<li class="active open">
<a href="#Url.Content(menu.MenuUrl)">
<span class="title"> #menu.Name </span>
<span class="selected"></span>
</a>
</li>
}
else {
<li class="main-menu-selection">
<a href="#menu.MenuUrl">
<span class="title">#menu.Name</span>
<i class="fa fa-chevron-down pull-right"></i>
<span class="selected"></span>
</a>
#if (sublist.Count > 0) {
<ul class="sub-menu">
#foreach (var sub in sublist) {
<li class="sub-menu-selection">
<a href="#Url.Content(sub.MenuUrl)">
<span class="title"> #sub.Name </span>
</a>
</li>
}
</ul>
}
</li>
}
count++;
}
</ul>
Try using stopPropagation:
$('.main-navigation-menu').on('click', '.sub-menu-selection', function(e){
var index;
e.stopPropagation();
$('.min-navigation-menu .active').removeClass('active');
$(e.currentTarget).addClass('active');
});
More info here

Categories

Resources