I have a dropdown menu with top level and two sub levels. The thing is that the sub levels work just fine, I can click on them and it takes me to the page I selected. The problem is with the top level, when I hover over it it displays the submenus but when I click on it it doesn't take me to the page.
var menu_Sub = $(".menu-has-sub");
var menu_Sub_Li;
$(".mobile-device .menu-has-sub").find(".fa:first").removeClass("fa-angle-right").addClass("fa-angle-down");
menu_Sub.click(function() {
if ($(".header").hasClass("mobile-device")) {
menu_Sub_Li = $(this).parent("li:first");
if (menu_Sub_Li.hasClass("menu-opened")) {
menu_Sub_Li.find(".sub-dropdown:first").slideUp(function() {
menu_Sub_Li.removeClass("menu-opened");
menu_Sub_Li.find(".menu-has-sub").find(".fa:first").removeClass("fa-angle-up").addClass("fa-angle-down");
});
} else {
$(this).find(".fa:first").removeClass("fa-angle-down").addClass("fa-angle-up");
menu_Sub_Li.addClass("menu-opened");
menu_Sub_Li.find(".sub-dropdown:first").slideDown();
}
return false;
} else {
return false;
}
});
menu_Sub_Li = menu_Sub.parent("li");
menu_Sub_Li.hover(function() {
if (!($(".header").hasClass("mobile-device"))) {
$(this).find(".sub-dropdown:first").stop(true, true).fadeIn("fast");
}
}, function() {
if (!($(".header").hasClass("mobile-device"))) {
$(this).find(".sub-dropdown:first").stop(true, true).delay(100).fadeOut("fast");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="nav-menu">
<ul class="nav-menu-inner">
<li>
Home
</li>
<li>
<a class="menu-has-sub" href="about-us">About us <i class="fa fa-angle-down"></i></a>
<!-- Dropdown -->
<ul class="sub-dropdown dropdown">
<li>
<a class="menu-has-sub" href="clients-case-studies">Clients and Case Studies</a>
</li>
</ul>
<!-- End Dropdown -->
Any help would be appreciated. Thank you.
The problem arises in your return false call at the end of your first if statement:
menu_Sub.click(function () {
if ($(".header").hasClass("mobile-device")) {
menu_Sub_Li = $(this).parent("li:first");
if (menu_Sub_Li.hasClass("menu-opened")) {
...
}
else {
return false; // this prevents the default click action from occuring
}
});
What you are saying here is basically, if I click on the .menu-has-sub link and it doesn't have a .mobile-device class, I want it to return false.
That essentially means event.preventDefault() - read this SO answer for a great explanation event.preventDefault() vs. return false
But that seems to be your problem, be careful when preventing the default action on links, if you want them to go somewhere.
Here is a fiddle with the line commented out.
Related
I am developing an angular 5 project. My home page is composed by many components. In navbarComponent I have a dropdown list.
When the dropdown list is open, on clicking outside it, I would like it to close automatically.
This is my code:
ngOnInit() {
this.showMenu = false;
}
toggle() {
this.showMenu = !this.showMenu;
}
<div *ngIf="isConnect" class=" userStyle dropdown-toggle " (click)="toggle()">
<ul class="dropdown-menu subMenu" role="menu" *ngIf="showMenu">
<li (click)="profile()" class="subMenuItem"> PROFILE</li>
<li (click)="administration()" class="subMenuItem subMenuItem-last">ADMINISTRATION</li>
<li class="subMenuItem subMenuItem-last"><button class="btn blue-btn" (click)="logout()" ><mat-icon mat-list-icon fontIcon="icon-logout"></mat-icon>LOGOUT</button></li>
</ul>
</div>
This is how I implemented it in my project. First we need to bind click event on window in ngOnInit hook.
ngOnInit() : void {
this.windowClickSubscription = Observable
.fromEvent(window, "click")
.subscribe(this.handleWindowClick)
}
Now whenever there is a click on window our this.handleWindowClick will be called, lets add implementation of this method.
handleWindowClick(res: any) {
let target: any = res.target;
let threshold: number = 0;
while(target && target.className != 'grouped-control' && threshold <= 4) {
target = target.parentElement;
threshold++;
}
if(target && target.className != 'grouped-control') this.hasOptions = false;
}
This function will search for parent of event target until it finds grouped-control which we need to close when there is a click on window excluding this element. So if we fount that element we do nothing else we close it using hasOptions flag.
Finally we need to unbind that event on ngDestroy
ngOnDestroy(): void {
this.windowClickSubscription && this.windowClickSubscription.unsubscribe();
}
Now ofcourse you need to define this.windowClickSubscription property in your component and bind reference of component to function handleWindowClick in your constructor
Edit
To bind reference of constructor add the following line in your constructor
constructor() {
this.handleWindowClick = this.handleWindowClick.bind(this);
}
This will allow you to pass this function as callback handler and it will be executed with reference of your component.
Since we can show hide html with help of *ngIf I am toggling my control which I need to hide using flag this. hasOptions
When you open Dropdown adds any class like 'open' with class 'dropdown-toggle' and when you close dropdown removes that class. If you click outside the dropdown area it will close the dropdown.
I have achieved using below code
<div class="drop-menu">
<a class="dropdown-toggle" title="Filter" (click)="openDropdown()">
<span class="fa fa-arrow"></span>
</a>
<ul class="dropdown-menu subMenu" role="menu" *ngIf="showMenu">
<li (click)="profile()" class="subMenuItem"> PROFILE</li>
<li (click)="administration()" class="subMenuItem subMenuItem-last">ADMINISTRATION</li>
<li class="subMenuItem subMenuItem-last"><button class="btn blue-btn" (click)="logout()" ><mat-icon mat-list-icon fontIcon="icon-logout"></mat-icon>LOGOUT</button></li>
</ul>
</div>
Code for component.ts file:
constructor(private renderer: Renderer2) { }
ngOnInit() {
const selectDOM = document.getElementsByClassName('dropdown-toggle')[0];
this.renderer.listen('document', 'click', (evt) => {
const eventPath = evt.path;
const hasClass = _.where(eventPath, { className: 'drop-menu' });
if (hasClass.length <= 0) {
this.renderer.removeClass(selectDOM, 'open');
}
});
}
openDropdown() {
const selectDOM = document.getElementsByClassName('dropdown-toggle')[0];
if (selectDOM.classList.contains('open')) {
this.renderer.removeClass(selectDOM, 'open');
} else {
this.renderer.addClass(selectDOM, 'open');
}
}
Add a TemplateRef-Id to your menu:
<ul #menuRef class="dropdown-menu subMenu" role="menu" *ngIf="showMenu">
....
</ul>
Get that TemplateRef in Code:
#ViewChild('menuRef') menuRef: TemplateRef<any>;
Then you have to register a global (on document level) click event:
#HostListener('document:click', ['$event'])
hideMenu(event) {
if (!this.menuRef.nativeElement.Contains(event.target) {
if (this.showMenu) {
this.showMenu = false;
}
}
}
If the click was outside of your dropdown, you set showMenu=false and your menu closes.
But why not use a component for your dropdown? ng-select does all of that automatically.
I've got bootstrap4 menu like this:
<ul class="navbar-nav ml-auto">
<li class="nav-item"><a class="nav-link" href="#introduction">INTRODUKTION <span class="sr-only">(current)</span></a></li>
</ul>
Default scroll spy adds active to nav-link (a) I need to change this, becouse my active should be after nav-item (li). Can I do that ?
You can see this here:
Example
When I click, everything goes ok - but on scroll - active is a href.
By default .active class will be added to only anchor tags.
Try something like this for your requirement
$('[data-spy="scroll"]').on('activate.bs.scrollspy', function () {
$(".navbar-nav .active").removeClass("active").parent().addClass("active");
})
Add attribute data-spy="scroll"
on <div class="container"> the parent of section with id="introduction"
like
<div class="container" data-spy="scroll">
I found solution. I need just to add new event (cssClassChanged) - and working !
(function(){
// Your base, I'm in it!
var originalAddClassMethod = jQuery.fn.addClass;
jQuery.fn.addClass = function(){
// Execute the original method.
var result = originalAddClassMethod.apply( this, arguments );
// trigger a custom event
jQuery(this).trigger('cssClassChanged');
// return the original result
return result;
}
})();
and then
$(".nav-link").bind('cssClassChanged' , function(e) {
$(".nav-item").each( function() {
if( $(this).hasClass("active") == true ) {
$(this).removeClass("active");
}
});
$(this).removeClass("active").parent().addClass("active");
});
I am using 'slideToggle' to open a couple divs on a site and want to ensure all of the divs are closed before another is opened. Is there a way to run a if..then to ensure a toggled div isn't open before opening another?
Here is my script;
<script type="text/javascript">
$(function()
{
$("a#toggle").click(function() {
$("#contact").slideToggle(500);
return false;
});
$("a#toggle_about").click(function(){
$("#about").slideToggle(500);
return false;
});
});
</script>
Calling tag;
<li>Contact Me</li>
And called div;
<div id="contact">blah, blah...</div>
And CSS;
#contact{display: none; padding: 7px; font-size: 14px;}
Thanks,
------EDIT------
This seems to work ok, I can control the transition by setting speed to 500 or 0. It just seems like a lot of code for a simple if..then.
Thanks for the suggestions and possible solutions.
<script type="text/javascript">
$(function()
{
$("a#toggle").click(function(){
if ($("#about").is(':hidden')){
$("#contact").slideToggle(500);
return false;
}else{
$("#about").slideToggle(500);
$("#contact").slideToggle(500);
return false;
}
});
$("a#toggle_about").click(function(){
if ($("#contact").is(':hidden')){
$("#about").slideToggle(500);
return false;
}else{
$("#contact").slideToggle(500);
$("#about").slideToggle(500);
return false;
}
});
});
</script>
Fiddle Example
If you add appropriate classes to your html and change the href to target the div it needs to open, you can significantly simplify your code.
<ul>
<li>Contact Me</li>
<li>About Me</li>
</ul>
<div id="contact" class="toggleable">blah, blah...</div>
<div id="about" class="toggleable">blah, blah...</div>
Now you can handle both links with a single event.
$(".toggler").click(function (e) {
e.preventDefault();
var target = $(this).attr("href");
$(".toggleable").not(target).hide();
$(target).slideToggle();
});
the end result is when you click on "Contact Me", about will hide if it is open, and contact will show if it is hidden or hide if it is shown.
http://jsfiddle.net/nYLvw/
You could implement a helper function to collapse any visible elements with a certain class, and then call that every time you're about to toggle a div.
The markup:
<div id="contact" class="toggle-content">blah, blah...</div>
The code:
function hideToggleContent() {
$('.toggle-content:visible').slideUp( 500 );
}
$(function() {
$("#toggle").click( function() {
var isVisible = $("#contact").is(':visible');
hideToggleContent();
if( isVisible ) {
return false;
}
$("#contact").slideDown( 500 );
return false;
});
$("#toggle_about").click( function() {
var isVisible = $("#about").is(':visible');
hideToggleContent();
if( isVisible ) {
return false;
}
$("#about").slideDown( 500 );
return false;
});
});
You might also check out the jQuery UI accordion, it's default behavior accomplishes the same. http://jqueryui.com/accordion/
UPDATE: Added Fiddle Link For Example
There are several ways to solution this problem.
Whenever you are tweening for effect, and you want to only tween if not already tweening, you will want to track the state of your tween.
Typically, you might have a trigger/toggler, and a target. I like to use closures to accomplish the state tracking. I might use something like this:
$(function () {
// closures
var $togglers = $('[selector][, selector]');
var $target = $('[selector]');
$target.tweening = false;
var tweenStop = function () {
$target.tweening = false;
};
var togglerClick = function () {
if (!$target.tweening) {
$target.tweening = true;
$target.slideToggle(500, tweenStop);
}
};
// handle the event
$togglers.click(togglerClick);
});
>> SAMPLE FIDDLE <<
I'm trying to make a drop down menu - upon the first hit on div it should extend,upon second hit it should come back where it was.I'm very new to javascript so I'm not really sure where I went wrong it looks perfect to me,the code:
$(document).ready(function() {
$("#firstList").hide();
$("#firstExtend").click(function()
{
if(("#firstList").hide == true)
{
$("#firstList").show("blind",250);
}
else
{
$("#firstList").hide("fade",250);
}
});
});
HTML:
<div id="firstExtend" class="list">Praplesti</div>
<ul id="firstList">
<li class="list">Nium</li>
<li class="list">cia</li>
<li class="list">kazkas</li>
<li class="list">tur</li>
<li class="list">but cj</li>
<li class="list">tikiuosiveiks</li>
</ul>
</div>
the if (object.hide) clause is a bit off. You can use .is(":property") to check. So in your case, do:
if ( $("#firstList").is(":visible") )
try this:
$(document).ready(function () {
$("#firstList").hide();
$("#firstExtend").click(function () {
if (("#firstList").is(':hidden')) {
$("#firstList").show("blind", 250);
} else {
$("#firstList").hide("fade", 250);
}
});
});
I am working on a web site. The type of menu that I want to create is one where you click on something in the menu, and a submenu pops up. But then you can also hover over any other menu item and another submenu will come up, hiding the first one you clicked. You can click anywhere to close the submenu.
I hope that was clear enough, and would appreciate any help you can give.
Here's my very, very simple, cheap, brief, ugly, lazy, father-disappointing version. It uses jQuery, and it probably doesn't actually look anything like what you wanted. But it accomplishes (I think) the one important thing: "locking" the sub-menu open until either another one is opened, or the user clicks somewhere else on the page.
The HTML looks like this...
<ul>
<li>
<a class="author" href="#">Menu Item 1</a>
<ul class="books">
<li><a class="book" href="#">Sub-Menu Item 1</a></li>
<li><a class="book" href="#">Sub-Menu Item 2</a></li>
</ul>
</li>
<!-- ... -->
</ul>
...and here's the JavaScript:
(function ($) {
var $current,
closeSubMenu = function () {
if ($current) {
$current.slideUp();
}
},
openSubMenu = function (e) {
var $books = $(this).next();
e.preventDefault();
e.stopPropagation();
if (!$current || $current[0] !== $books[0]) {
closeSubMenu();
$current = $books;
$books.slideDown();
}
};
$(document).click(function (e) {
var $target = $(e.target);
if ($target.hasClass('author')) {
openSubMenu.call(e.target, e);
} else if ($target.hasClass('book')) {
e.preventDefault();
} else {
closeSubMenu();
$current = null;
}
});
$('.books').slideUp();
}(jQuery));
If nothing else, it should help give you some ideas for how you do decide to do it.