I can't seem to get my dropdown code to function properly - javascript

I am trying to create a drop down menu that when the drop down button is clicked it shows the sub menu. When I click anywhere else though it should hide the sub menu.
Here is my code:
function initMainNavigation( container ) {
container.find( '.dropdown-toggle' ).click(function(e){
var dropdown = $( this );
e.preventDefault();
dropdown.next( '.children, .sub-menu' ).toggleClass( 'toggled-on' );
});
$("body").click(function(){
var dropdown = container.find( '.dropdown-toggle' );
dropdown.next( '.children, .sub-menu' ).removeClass('toggled-on');
});
}
initMainNavigation( $( '.main-navigation' ) );
But when I click the dropdown toggle the sub menu won't show. When I debugged it in firebug, the $("body").click() event is triggered as well. I am guessing it's because the '.main-navigation' is inside the "body".
I know that it works if I remove $("body").click(). However I can't click else where to hide the sub menu.

Your body click event bubbles to the .dropdown-toggle container so when you click .dropdown-toggle you trigger both events
function initMainNavigation( container ) {
container.find( '.dropdown-toggle' ).click(function(e){
var dropdown = $( this );
e.preventDefault();
dropdown.next( '.children, .sub-menu' ).toggleClass( 'toggled-on' );
});
$("body").click(function(e){
var dropdown = container.find( '.dropdown-toggle' );
if(!$(e.target).closest('.dropdown-toggle').length) {//trigger the toggle only if the element is not .dropdown-toggle or a child of it
dropdown.next( '.children, .sub-menu' ).removeClass('toggled-on');
}
});
}
initMainNavigation( $( '.main-navigation' ) );

Related

I have a named function which works great on click. How can I run it on a specific element when the page loads?

So, I have a function called runFilter. It works great when I run it on click. If you look at the line underneath "on load, run the filter," that doesn't work at all. If it was a built-in function like .css() then it would work fine, but this isn't a built-in function and I've already failed at extending jQuery to make it one.
I'm probably doing something very obvious wrong here, but what I want to happen is for the function to fire once after the page is loaded, targeting this specific link: ul > li:first-child a.
jQuery(document).ready(function( $ ) {
function runFilter( event ) {
console.log( this );
event.preventDefault();
//* add active class on the active nav item
$( 'ul.attractions-filters a' ).removeClass( 'active' );
$( this ).addClass( 'active' );
//* add active class for visible things
term = $( this ).attr( 'data-term' );
$( '.type-attractions' ).removeClass( 'active' );
$( '.attractiontype-' + term ).addClass( 'active' );
}
// Show everything once the page is fully loaded
$( '.type-attractions' ).addClass( 'active' );
//* On load, run the filter
// $( 'ul.attractions-filters:first a' ).on( 'load', runFilter );
//* On click, run the filter
$( 'ul.attractions-filters a' ).on( 'click', runFilter );
});
While it's not clear which A of which UL you're actually trying to refer to, there are a bunch of different ways of doing it:
The example below depends on a few things:
jQuery will call any method attached through .on via the .click
method. It automatically binds it to the function.
jQuery will let you invoke known events through the .trigger method. It automatically binds it to the function
querySelector only returns the first element that matches a selector (may be easier to read than the equivalent jQuery selector)
let selector = 'ul.attractions-filters a';
let firstSelector = 'ul.attractions-filters:first a';
let firstChildSelector = 'ul.attractions-filters a:first';
let firstChildSelectorJQ = 'ul.attractions-filters:first a:first';
let whatYouAskedFor = 'ul > li:first-child a'
$(function() {
function runFilter() {
console.log(this)
}
$(selector).on('click', runFilter);
console.log( "This selector will click all A elements in the first UL with class 'attractions-filters'")
$(firstSelector).click();
$(firstSelector).trigger('click');
console.log( "This selector will click the first A element in every UL with class 'attractions-filters'")
$(whatYouAskedFor).click();
$(whatYouAskedFor).trigger('click');
console.log("These selectors will click the first A element in the first UL with class 'attractions-filters'")
$($(firstSelector)[0]).click();
$($(firstSelector)[0]).trigger('click');
$(firstChildSelector).click();
$(firstChildSelector).trigger('click');
runFilter.bind($(firstSelector)[0])();
console.log("These selectors will select only the first child of the first UL of class 'attractions-filters' and click it")
$(firstChildSelectorJQ).click();
$(firstChildSelectorJQ).trigger('click');
runFilter.bind($(firstChildSelectorJQ)[0])();
runFilter.bind(document.querySelector(selector))();
console.log("This selector is the requirement you gave")
runFilter.bind(document.querySelector(whatYouAskedFor))();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>What You Asked For</li>
</ul>
<ul class="attractions-filters">
<li>UL 1, LI 1</li>
<li>UL 1, LI 2</li>
</ul>
<ul class="attractions-filters">
<li>UL 2, LI 1</li>
<li>UL 2, LI 2</li>
</ul>
You're very close!
Your code, modified below, with a few comments:
// altered to be a briefer document ready (Still no-conflict safe!)
jQuery(function( $ ) {
function runFilter( event ) {
event.preventDefault();
// add active class on the active nav item
$( 'ul.attractions-filters a' ).removeClass( 'active' );
$( this ).addClass( 'active' );
// add active class for visible things
term = $( this ).attr( 'data-term' );
$( '.type-attractions' ).removeClass( 'active' );
$( '.attractiontype-' + term ).addClass( 'active' );
}
// Show everything once the page is fully loaded
$( '.type-attractions' ).addClass( 'active' );
// On click, run the filter
$( 'ul.attractions-filters a' ).on( 'click', runFilter );
// NOTE: Choose ONE of the following three methods:
// Method #1: using trigger
$( 'ul.attractions-filters:first a' ).trigger( 'click' );
// Method #2: using click
$( 'ul.attractions-filters:first a' ).click();
// Method #3: better yet "chain" the methods to reduce duplicate code...
// NOTE: this replaces BOTH your .on('click') AND the .trigger or .click above...
$( 'ul.attractions-filters a' )
.on( 'click', runFilter )
.trigger( 'click');
});

Prevent A Parent Action With Bootstrap Popover

I have the following JavaScript:
$( ".aa-list-menu-item-heading" ).click(
function()
{
$( this ).find( ".aa-collapse" ).toggleClass( "glyphicon-chevron-left glyphicon-chevron-down" );
$( this ).next( ".row" ).slideToggle();
}
);
$("[data-toggle=popover]").popover();
The popover link is within a child div with class .aa-list-menu-item-heading
When I click the popover, it works, but the $( ".aa-list-menu-item-heading" ).click() runs
How can I prevent the parent child popover actioning the parent .click()?
You "can't", but you could check if the target of your click is the popover in your DIV click event handler and skip the execution just in case.
$( ".aa-list-menu-item-heading" ).click(
function(e)
{
if ($(e.target).data('toggle') !== 'popover'){
$( this ).find( ".aa-collapse" ).toggleClass( "glyphicon-chevron-left glyphicon-chevron-down" );
$( this ).next( ".row" ).slideToggle();
}
}
);

Javascript - Hide a div with a reset button

I need a UL, containing the search results (ul.job_listings) to hide after a reset button is pressed.
So far a reset has been set up to reset the search form:
$( '.job_filters' ).on( 'click', '.reset', function () {
var target = $( this ).closest( 'div.job_listings' );
var form = $( this ).closest( 'form' );
form.find( ':input[name="search_keywords"], :input[name="search_location"], .job-manager-filter' ).not(':input[type="hidden"]').val( '' ).trigger( 'chosen:updated' );
form.find( ':input[name^="search_categories"]' ).not(':input[type="hidden"]').val( 0 ).trigger( 'chosen:updated' );
$( ':input[name="filter_job_type[]"]', form ).not(':input[type="hidden"]').attr( 'checked', 'checked' );
target.triggerHandler( 'reset' );
target.triggerHandler( 'update_results', [ 1, false ] );
job_manager_store_state( target, 1 );
return false;
} );
How would I add to it to also hide the results div?
Thanks for any help,
Liz.
Since you seem to be using jQuery, it you could just add
target.hide();
before the return statement.
edit - see comments above :-)

How to dismiss dropdown menu in WordPress template on new page

I'm working on a Wordpress template and one of the features is a dropdown menu in the header. You click the arrow to open it, and it remains open until you click the arrow to close it. But, when you click on one of the links, it still remains open on the next page. You have to click the arrow to close it.
I would like the dropdown menu to automatically close when navigating to a new page. Here is my js for the navigation... I'm following a tutorial from Lynda so I didn't write this code, but I haven't had enough experience with js to know which section of the code is doing what exactly.
Please let me know if you need any other information.
function initMainNavigation( container ) {
// Add dropdown toggle that display child menu items.
container.find( '.menu-item-has-children > a' ).after( '<button class="dropdown-toggle" aria-expanded="false">' + screenReaderText.expand + '</button>' );
// Toggle buttons and submenu items with active children menu items.
container.find( '.current-menu-ancestor > button' ).addClass( 'toggle-on' );
container.find( '.current-menu-ancestor > .sub-menu' ).addClass( 'toggled-on' );
container.find( '.dropdown-toggle' ).click( function( e ) {
var _this = $( this );
e.preventDefault();
_this.toggleClass( 'toggle-on' );
_this.next( '.children, .sub-menu' ).toggleClass( 'toggled-on' );
_this.attr( 'aria-expanded', _this.attr( 'aria-expanded' ) === 'false' ? 'true' : 'false' );
_this.html( _this.html() === screenReaderText.expand ? screenReaderText.collapse : screenReaderText.expand );
} );
}
initMainNavigation( $( '.main-navigation' ) );
// Re-initialize the main navigation when it is updated, persisting any existing submenu expanded states.
$( document ).on( 'customize-preview-menu-refreshed', function( e, params ) {
if ( 'primary' === params.wpNavMenuArgs.theme_location ) {
initMainNavigation( params.newContainer );
// Re-sync expanded states from oldContainer.
params.oldContainer.find( '.dropdown-toggle.toggle-on' ).each(function() {
var containerId = $( this ).parent().prop( 'id' );
$( params.newContainer ).find( '#' + containerId + ' > .dropdown-toggle' ).triggerHandler( 'click' );
});
}
});
I know that this question is almost a year old, but I wanted to go ahead and post an answer just in case someone needs it in the future.
The following lines from your code are what's causing the toggles to stay open when you go to a new page.
// Toggle buttons and submenu items with active children menu items.
container.find( '.current-menu-ancestor > button' ).addClass( 'toggle-on' );
container.find( '.current-menu-ancestor > .sub-menu' ).addClass( 'toggled-on' );
When you navigate to a page that is part of a sub-menu, these lines automatically add the 'toggle-on' class to the appropriate toggle button and parent sub-menu of that page. If you comment out those lines, the sub-menus will close when you navigate to a new page.

jQuery multiple toggle hide all / show only one

Hello Dear Programmers,
I have a header menu, with "Search", "Language", "Time" toggle functions.
Regarding display onClick it works correctly, but I need If I Click on "Search" show only "Search" and hide all "Language", "Time".
My code
.js
$( '.search-toggle' ).on( 'click.twentyfourteen', function( event ) {
var that = $( this ),
wrapper = $( '.search-box-wrapper' );
that.toggleClass( 'active' );
wrapper.toggleClass( 'hide' );
if ( that.is( '.active' ) || $( '.search-toggle .screen-reader-text' )[0] === event.target ) {
wrapper.find( '.search-field' ).focus();
}
} );
$( '.language-toggle' ).on( 'click.twentyfourteenn', function( event ) {
var that = $( this ),
wrapper = $( '.language-box-wrapper' );
that.toggleClass( 'active' );
wrapper.toggleClass( 'hide' );
} );
$( '.time-toggle' ).on( 'click.twentyfourteennn', function( event ) {
var that = $( this ),
wrapper = $( '.time-box-wrapper' );
that.toggleClass( 'active' );
wrapper.toggleClass( 'hide' );
} );
and html
<div class="search-toggle">
<?php _e( 'Search', 'twentyfourteen' ); ?>
</div>
<div class="language-toggle">
<?php _e( 'Search', 'twentyfourteenn' ); ?>
</div>
<div class="time-toggle">
<?php _e( 'Search', 'twentyfourteennn' ); ?>
</div>
<div id="search-container" class="search-box-wrapper hide">
<div class="search-box">
<?php get_search_form(); ?>
</div>
</div>
<div id="language-container" class="language-box-wrapper hide">
<div class="language-box">
language
</div>
</div>
<div id="time-container" class="time-box-wrapper hide">
<div class="time-box">
time
</div>
</div>
If I understand what you mean you want to hide two different elements when clicking search you want the others to hide?
By using add you can group elements together then add classes to show or hide:
$('#element1_id').add('#element2_id').removeClass('show');
$('#element1_id').add('#element2_id').addClass('hide');
or just straight up hide them with jQuery.
$('#element1_id').add('#element2_id').hide();
You could also give the element you want to hide together a common class name:
ie: toggle
then you can simply use the class toggle to hide them:
$('.toggle').removeClass('show');
$('.toggle').addClass('hide');
or
$('.toggle').hide();
i think this will hide other parts, i have not tried this but hope will work for u
$( '.search-toggle' ).on( 'click.twentyfourteen', function( event ) {
var that = $( this ),
wrapper = $( '.search-box-wrapper' );
that.toggleClass( 'active' );
$( '.search-box-wrapper' ).hide();
$( '.time-box-wrapper' ).hide();
$( '.language-box-wrapper' ).hide();
if ( that.is( '.active' ) || $( '.search-toggle .screen-reader-text' )[0] === event.target ) {
wrapper.find( '.search-field' ).focus();
}
} );
$( '.language-toggle' ).on( 'click.twentyfourteenn', function( event ) {
var that = $( this ),
wrapper = $( '.language-box-wrapper' );
$( '.search-box-wrapper' ).hide();
$( '.time-box-wrapper' ).hide();
$( '.language-box-wrapper' ).hide();
that.toggleClass( 'active' );
} );
$( '.time-toggle' ).on( 'click.twentyfourteennn', function( event ) {
var that = $( this ),
wrapper = $( '.time-box-wrapper' );
$( '.search-box-wrapper' ).hide();
$( '.time-box-wrapper' ).hide();
$( '.language-box-wrapper' ).hide();
that.toggleClass( 'active' );
} );
This should solve the problem. You can view working demo with this link Working Demo
Summary of what I did.
I added some text as link in the html (just for testing)
I added .hide() Jquery class to hide the three wrapper classes before the click events
I added a little bit of animation to wrapper.toggle('slow')
I changed wrapper.toggleClass('slow') to wrapper.toggle('slow')
$('.search-box-wrapper').hide();
$('.language-box-wrapper').hide();
$('.time-box-wrapper').hide();
$('.search-toggle').on('click.SearchLink', function (event) {
var that = $(this),
wrapper = $('.search-box-wrapper');
that.toggleClass('active');
wrapper.toggle('slow');
if (that.is('.active') || $('.search-toggle .screen-reader-text')[0] === event.target) {
wrapper.find('.search-field').focus();
}
});
$('.language-toggle').on('click.LangLink', function (event) {
var that = $(this),
wrapper = $('.language-box-wrapper');
that.toggleClass('active');
wrapper.toggle('slow');
});
$('.time-toggle').on('click.TimeLink', function (event) {
var that = $(this),
wrapper = $('.time-box-wrapper');
that.toggleClass('active');
wrapper.toggle('hide');
});

Categories