On hover closing specific list element - javascript

<ul class="open-close1" id="reportType">
<li class="active">
<div id="subcats">
<ul>
<li>
<img class="loading-spinner" src="store/$vendorSettingsDTO.vendorId/assets/themes/$vendorSettingsDTO.skinname/images/loading.gif" height="18"/>
</li>
</ul>
</div>
</li>
</ul>
<script>
jQuery(document).ready(function($){
jQuery.getJSON('subcat.ajx?vid=$vendorSettingsDTO.vendorId&cid=$catid', function(data) {
//Render subcatergories using Mustache.js (https://github.com/janl/mustache.js)
var subcat_mustache =
'<ul>\
<a style="font-size:14px; font-weight:bold; color:#0073B3;" class="opener"href="{{URL}}">{{description}}</a>\
{{#childs}}\
{{> child}}\
{{/childs}}\
</ul>';
var partials = {
child:
'<li>\
<a class="opener" href="{{URL}}">{{description}}</a>\
<div class="subnav1 hidden">\
<ul>\
{{#childs}}\
{{> child}}\
{{/childs}}\
</ul>\
</div>\
</li>'
}
jQuery("#subcats").html(Mustache.render(subcat_mustache, data, partials));
});
});
</script>
<script>
$(document).ready(function() {
$(".open-close1").hover(function (){
//$(this).children('.subnav1').toggle();
//console.log("$(this).children('.subnav1') "+$(this).children('.subnav1'));
//$(".subnav1", this).toggle();
$(this).find('.subnav1').toggle(); // p00f
});
});
</script>
This is the code I have in case of my category page. I implemented a logic to toggle the block on hover. But entire list of categories is toggling instead of specific list on which it is hovered.
Please help me its IRRITATING me. Thanks a lot for your help in advance.

I assume your rendered html like below;
<ul class="open-close1" id="reportType">
<li class="active">
<div id="subcats">
<ul>
<li>
<a class="opener" href="#">Item1</a>
<div class="subnav1 hidden">
<ul>
<li>Item1-1</li>
<li>Item1-2</li>
<li>Item1-3</li>
</ul>
</div>
</li>
<li>
<a class="opener" href="#">Item2</a>
<div class="subnav1 hidden">
<ul>
<li>Item2-1</li>
<li>Item2-2</li>
<li>Item2-3</li>
</ul>
</div>
</li>
<li>
<a class="opener" href="#">Item3</a>
<div class="subnav1 hidden">
<ul>
<li>Item3-1</li>
<li>Item3-2</li>
<li>Item3-3</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</li>
</ul>
You can use following js for above html structure;
$(".opener").hover(function (){
$(this).next().toggle();
});
Here is a working demo: http://jsfiddle.net/cubuzoa/EKu2q/
Edit: On your site, category section you mentioned loaded with ajax. So you need to run function after ajax load like below;
<script>
jQuery(document).ready(function($){
jQuery.getJSON('subcat.ajx?vid=$vendorSettingsDTO.vendorId&cid=$catid', function(data) {
//Render subcatergories using Mustache.js (https://github.com/janl/mustache.js)
var subcat_mustache =
'<ul>\
<a style="font-size:14px; font-weight:bold; color:#0073B3;" class="opener"href="{{URL}}">{{description}}</a>\
{{#childs}}\
{{> child}}\
{{/childs}}\
</ul>';
var partials = {
child:
'<li>\
<a class="opener" href="{{URL}}">{{description}}</a>\
<div class="subnav1 hidden">\
<ul>\
{{#childs}}\
{{> child}}\
{{/childs}}\
</ul>\
</div>\
</li>'
}
jQuery("#subcats").html(Mustache.render(subcat_mustache, data, partials));
$(".opener-parent").parent('li').hover(function (){
$(this).find('subnav1').toggle();
});
});
});
</script>
I have also give class name for upper categories as opener-parent and updated js code
Updated demo: http://jsfiddle.net/R9KLz/4/
Final Result: If you do not want to add opener-parent class, you can use following;
$("#subcats ul li").hover(function (){
if ($(this).find('.subnav1').first().find("ul").has("li").length) {
$(this).find('.subnav1').first().toggle();
}
});
Here is a working demo: http://jsfiddle.net/cubuzoa/R9KLz/5/

Something I noticed, I think you have an extra <div> in your list markup.
<ul class="open-close1" id="reportType">
<li class="active">
<div id="subcats">
<ul>
<li><img class="loading-spinner" src="store/$vendorSettingsDTO.vendorId/assets/themes/$vendorSettingsDTO.skinname/images/loading.gif" height="18"/></li>
</ul>
</div>
<!--</div>-->
</li>
</ul>
Also, I just a hunch, but I think you need to be more specific in which element inside of your class you want to talk to. For example, you have this:
$(this).find('.subnav1').toggle();
But I think you need something more along the lines of:
$(this).find('.subnav1 ul').toggle();
Or, if possible, you could give your list(s) some sort of hook to make it even easier to talk to.

Related

Loop through DOM elements with JQuery to assign a click handler

I need to loop through the DOM with JQuery, and add a click handler to multiple parent elements that contain a child that will also be given a slideToggle(). I have the logic working fine when I add the click handlers manually, but now I need to be able to dynamically do this to multiple parent elements.
Here is my HTML:
<div class="map-poi-nav">
<ul class="map-poi-nav-dropdown">
//Parent #1
<li class="sub-menu-link" id="sub-menu-link-1">
<a href="#">
<img src="https://svgshare.com/i/ADc.svg"> Activities
</a>
</li>
<li class="sub-menu">
<ul class="sub-menu-list" id="sub-menu-list-1">
<li><a><span>•</span>Golden State Park</a></li>
<li><a><span>•</span>Sunrise Oaks City Park</a></li>
</ul>
</li>
</ul>
<ul class="map-poi-nav-dropdown">
//Parent #2
<li class="sub-menu-link" id="sub-menu-link-2">
<a href="#">
<img src="https://svgshare.com/i/ADc.svg"> Dining
</a>
</li>
<li class="sub-menu">
<ul class="sub-menu-list" id="sub-menu-list-2">
<li><a><span>•</span>The Loft Grill</a></li>
<li><a><span>•</span>Fish Grill & Bar</a></li>
</ul>
</li>
</ul>
</div>
Basically, you click on .sub-menu-link to slideToggle() .sub-menu-list.
Here is the JS that I have working so far. It targets the id's manually currently, which feels gross:
$('#sub-menu-link-1').click(function() {
$('#sub-menu-list-1').slideToggle(100);
$(this).toggleClass('active-menu-link');
});
$('#sub-menu-link-2').click(function() {
$('#sub-menu-list-2').slideToggle(100);
$(this).toggleClass('active-menu-link');
});
My apologies if this is something very apparent to do in JQuery. I am not at all familiar with it, and it just so happens to be a requirement of this project.
you could simply use below code.
select all list items with class name and add listener. click will be attached to all elements
$('.sub-menu-link').click(function() {
$(this).slideToggle(100);
$(this).toggleClass('active-menu-link');
});
You already have classes, so just use them instead of the ids: use this to refer to the clicked element, .next() to get the next sibling (the li.sub-menu), and .find('.sub-menu-list') to get to the ul you want to toggle:
$('.sub-menu-link').click(function() {
const $subMenuList = $(this).next().find('.sub-menu-list');
console.log($subMenuList.text().trim());
$subMenuList.slideToggle(100);
$(this).toggleClass('active-menu-link');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="map-poi-nav">
<ul class="map-poi-nav-dropdown">
//Parent #1
<li class="sub-menu-link" id="sub-menu-link-1">
<a href="#">
<img src="https://svgshare.com/i/ADc.svg"> Activities
</a>
</li>
<li class="sub-menu">
<ul class="sub-menu-list" id="sub-menu-list-1">
<li><a><span>•</span>Golden State Park</a></li>
<li><a><span>•</span>Sunrise Oaks City Park</a></li>
</ul>
</li>
</ul>
<ul class="map-poi-nav-dropdown">
//Parent #2
<li class="sub-menu-link" id="sub-menu-link-2">
<a href="#">
<img src="https://svgshare.com/i/ADc.svg"> Dining
</a>
</li>
<li class="sub-menu">
<ul class="sub-menu-list" id="sub-menu-list-2">
<li><a><span>•</span>The Loft Grill</a></li>
<li><a><span>•</span>Fish Grill & Bar</a></li>
</ul>
</li>
</ul>
</div>
You can use jQuery's .next() like so:
$(".sub-menu-link").click(function() {
$(this).next(".sub-menu-link").slideToggle(100);
$(this).toggleClass("active-menu-link");
})
Or you can chain them and use ES6 arrow syntax to make it more concise:
$(".sub-menu-link").click(() => $(this).toggleClass("active-menu-link").next(".sub-menu-link").slideToggle(100));
You should try this if your list and link ids have similiar pattern as in the code you have shown
$('#sub-menu-link').click(function() {
var id = $(this).attr("id").replace("sub-menu-link", "")
$('#sub-menu-list-'+ id).slideToggle(100);
$(this).toggleClass('active-menu-link');
});

Need an element's parent index using jquery or javascript

I have three <ul>s that expand when their buttons are clicked. Not all three <ul>s will show up - only when there is a notification to show. I hard-coded the values for now, but I can instantiate them on an as-needed basis.
Right now, they cover each other when they expand. I would like the others to move when a list is expanded so they don't cover each other. I was thinking of getting the index of the one whose button is clicked and then resetting the bottom style of the others. I need to get the index of the <ul> parent of the button that was clicked, probably using jQuery but straight JavaScript is fine as well. Can anyone help?
Here is my code:
<div id="NotificationDiv">
<ul id="noticeLead" class="notification_base notification_Lead"><button id="notification_button">Lead Notice</button>
<div>
<li id="urlLead" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Lead #1</a>
</li>
<li id="urlLead" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Lead #2</a>
</li>
</div>
</ul>
<ul id="noticeTask" class="notification_base notification_Task"><button id="notification_button">Task Notice</button>
<div>
<li id="urlTask" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Task #5</a>
</li>
<li id="urlTask" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Task #6</a>
</li>
<div>
</ul>
<ul id="noticePolicy" class="notification_base notification_Policy"><button id="notification_button">Policy Notice</button>
<div>
<li id="urlPolicy" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Policy #3</a>
</li>
<li id="urlPolicy" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Policy #4</a>
</li>
</div>
</ul>
</div>
And in the $(document).ready, I have:
$('.notification_base').on('click', 'button', function(){
$(this).closest('.notification_base').find('.notification_urlNotice').slideToggle();
});
Try this:
var myParentId; //Here you'll store the id of the clicked element
$('.notification_base').on('click', 'button', function(){
$(this).closest('.notification_base').find('.notification_urlNotice').slideToggle();
myParentId = $(this).attr("id");
});
Thank you everyone for your input. I changed my structure to a table assigning .parent class to the header row and .child class to the data row and put this code in the jQuery ready function and it works great.
function getChildren($row) {
var children = [];
while($row.next().hasClass('child')) {
children.push($row.next());
$row = $row.next();
}
return children;
}
$('.parent').on('click', function() {
var children = getChildren($(this));
$.each(children, function() {
$(this).toggle();
})
});

JQuery hide/show not working as it should

I'm trying to make a drop down menu and have it open sub menus on click and close them on click, but I cannot even get it to hide my submenu to start off with on a click.
Here is my JQuery code:
$(document).ready(function(){
$("#timeli").click(function(){
$("#timeUlSub").hide();
});});
And this is my html code that I am trying to get to hide/show
<div class="timeline">
<ul>
<li id="timeli">1996
<ul id="timeUlSub">
<li>
<p class="timeline-date">1997</p>
<p class="timeline-description">This is in the submenu</p>
</li>
</ul>
</li>
<li>1999</li>
<li>2000</li>
<li>2004</li>
<li>2006</li>
<li>2007</li>
</ul>
</div>
Am I doing something wrong on the jquery end? Because from what I have looked on here this should be working, but it's not.
Using toggle() may be more effective:
$("#timeli").click(function(){
$("#timeUlSub").toggle();
});
Example Fiddle
$(document).ready(function(){
$("#timeli").on('click', function()
{
$("#timeUlSub").toggle();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="timeline">
<ul>
<li id="timeli">1996
<ul id="timeUlSub">
<li>
<p class="timeline-date">1997</p>
<p class="timeline-description">This is in the submenu</p>
</li>
</ul>
</li>
<li>1999</li>
<li>2000</li>
<li>2004</li>
<li>2006</li>
<li>2007</li>
</ul>
</div>
#timeUlSub is part of the #timeli li. Move it outside the li. In addition, jquery .slideToggle() is a better method than .hide().
Check if you have Jquery linked.
Try this out for conditional usage :
$(document).ready(function(){
$("#timeli").on('click', function(){
if($("#timeUlSub").is(':hidden')){
$("#timeUlSub").show();
} else {
$("#timeUlSub").hide();
}
});
});
<div class="timeline">
<ul>
<li id="timeli">1996
<ul id="timeUlSub">
<li>
<p class="timeline-date">1997</p>
<p class="timeline-description">This is in the submenu</p>
</li>
</ul>
</li>
<li>1999</li>
<li>2000</li>
<li>2004</li>
<li>2006</li>
<li>2007</li>
</ul>
</div>
#timeUlSub{
display:none;
}
$(document).ready(function(){
$("#timeli").click(function(){
$("#timeUlSub").toggle();
});});
jsfiddle: http://jsfiddle.net/shellyjindal/rxb56emp/

How to apply toggle?

here is my code of html on which i have to apply togle
<div class="contact-links contact-info">
<ul>
<li class="contact-link-list toggle-sub"><a data-toggle-handler="contact-details-2" href="#">Agent Details</a>
<ul data-toggle-group="contact-details-2" class="senf hidden">
<ul style="float:left">
<li style="margin-right:20px;">Office hours</li>
<li style="margin-right:20px;">Products offered</li>
<li>Languages</li>
<li>Visit Agent Site</a></li>
</ul>
<ul style='float:left; margin-left:-20px;'>
<li>Mon-Fri 9:00AM-5:00PM</li>
<li>Auto, Home</li>
<li>English, Spanish</li></ul>
</ul></li>
</ul>
</div>
and here is my code of jquery
$(document).ready(function(){
$(".contact-link-list").click(function(){
('.senf').slideToggle("fast");
});
});
here is my jsfiddle - http://jsfiddle.net/n7U6b/
please suggest me where i am wrong
There is no element in your example with a class of senf. Also you are missing a $ before your selector:
$('.senf').slideToggle("fast");
Edit
Here is an updated fiddle from your example. You are still missing the $, and you have a stray closing </a> tag in there, but you also need to add a class of senf to the item you want to toggle. For example:
<ul data-toggle-group="contact-details-2" class="hidden senf">
$(document).ready(function(){
$(".contact-link-list").click(function(){
$('.senf').slideToggle("fast");
});
});
You just missed a $ sign on '.senf'
Plus where is the item with class senf?? I might have missed it!

duplicate functions, how may I combine them?

I have a function that remains pretty much constant except for the changing class names. I was hoping to make the code a little less text heavy. How may I go about making it just a small function instead of repeating it n times. My concern is also about removing the active class for the last li that was clicked. I've provided only 2 instances here, but this code is repeated n number of times.Any ideas would be much appreciated.
$('a.app1-preview').click(function() {
//remove last active classes
$(".app2").removeClass('active');
$(".app2-preview").removeClass('active');
//Add active class for this
$(this).parent().addClass('active');
$(this).addClass('active');
$('.app-preview-2').fadeOut("slow", function () {
$('.app-preview-1').fadeIn("slow");
});
});
$('a.app2-preview').click(function() {
//remove last active classes
$(".app1").removeClass('active');
$(".app1-preview").removeClass('active');
//Add active class for this
$(this).parent().addClass('active');
$(this).addClass('active');
$('.app-preview-1').fadeOut("slow", function () {
$('.app-preview-2').fadeIn("slow");
});
});
HTML code:
<div class="app-container">
<ul class="apps">
<li class="app1">
<a title href="#" class="app1-preview blocklink">
<span>ANOTHER<br /> APP</span>
</a>
</li>
<li class="app2">
<a title href="#" class="app2-preview blocklink">
<span>SECOND<br /> APP</span>
</a>
</li>
</div>
Try to exploit the fact that you have .active class. ;) Preview - http://jsfiddle.net/evSqF/1/
js:
<script>
$('a.blocklink').click(function() {
var self = $(this);
$('.active').fadeOut('slow', function(){
$(this).removeClass('active');
self.fadeIn('slow');
self.addClass('active');
});
});
</script>
html:
<div class="app-container">
<ul class="apps">
<li class="app1">
<a title href="#" class="app1-preview blocklink">
<span>ANOTHER<br /> APP</span>
</a>
<div class="app-preview active">App1 preview</div>
</li>
<li class="app2">
<a title href="#" class="app2-preview blocklink">
<span>SECOND<br /> APP</span>
</a>
<div class="app-preview">App2 preview</div>
</li>
</ul>
</div>
Edit: After I got some caffeine, I noticed the problems with the setup. I've created a demo at JSFiddle. The markup will display a "header" for an app which will display the child description when clicked on, and hide the descriptions of other sibling's descriptions.
In this case, you can show the current element, and hide the siblings, which would be a cleaner solution as it scales as you at more app elements.
$(".app").click(function() {
var $self = $(this);
var $apps = $self.closest(".apps");
var $selfSiblings = $apps.children(".app").not($self);
$self.addClass(".active");
$self.find(".app-preview").addClass("active");
$selfSiblings.removeClass(".active");
$selfSiblings.find(".app-preview").removeClass("active").fadeOut("slow", function() {
$self.find(".app-preview").fadeIn("slow");
});
});​
I would also recommend rewriting your HTML as such:
<div class="app-container">
<ul class="apps">
<li class="app">
App 1<br />
<a title href="#" class="app-preview blocklink">
<span>PREVIEW 1</span>
</a>
</li>
<li class="app">
App 2<br />
<a title href="#" class="app-preview blocklink">
<span>PREVIEW 2</span>
</a>
</li>
<li class="app">
App 3<br />
<a title href="#" class="app-preview blocklink">
<span>PREVIEW 3</span>
</a>
</li>
</div>​
Write a function to make the functions for you:
function makeHandler(deactivate, fadeOut, fadeIn) {
return function() {
//remove last active classes
$(deactivate).removeClass('active');
//Add active class for this
$(this).parent().addClass('active');
$(this).addClass('active');
$(fadeOut).fadeOut("slow", function () {
$(fadeIn).fadeIn("slow");
});
});
Then:
$('a.app1-preview').click(makeHandler('.app2, .app2-preview', '.app-preview-2', '.app-preview-1'));
$('a.app2-preview').click(makeHandler('.app1, .app1-preview', '.app-preview-1', '.app-preview-2'));
You could probably simplify things further by re-thinking the naming conventions you've got.
I would suggest to define a single function:
function single(index_main, index_aux) {
// Does all your magic
}
$('a.app1-preview').click(function() {
single("1", "2");
});
$('a.app2-preview').click(function() {
single("2", "1");
});
And that does the trick.
I made a jsfiddle example for you. Have a look at it here, it uses as much code that you wrote as possible, so nothing that should surprise you will be there :)
http://jsfiddle.net/2ZPxx/
Basically I ended up with this HTML:
<div class="app-container">
<ul class="apps">
<li class="app1">
<a title href="#" class="app1-preview blocklink" id="app1">
<span>ANOTHER<br /> APP</span>
</a>
</li>
<li class="app2">
<a title href="#" class="app2-preview blocklink" id="app2">
<span>SECOND<br /> APP</span>
</a>
</li>
</div>
<div class="app-preview-app1 app-preview">App1 preview</div>
<div class="app-preview-app2 app-preview">App2 preview</div>
And this javascript:
$('.apps li a').click(function() {
var id = $(this).attr('id');
$('.apps li').removeClass('active');
//Add active class for this
$(this).parent().addClass('active');
$(this).addClass('active');
$('.app-preview').fadeOut("slow", function () {
$('.app-preview-'+id).fadeIn("slow");
});
});

Categories