I am working through an issue where I have a menu that is mutli levels deep. I am trying to get it so that if a first level element is clicked (add class .ubermenu-active) it will look for any other first level element with that class and remove it.
$('.ubermenu-item-level-0 span').on('click',function() {
var target = $('.ubermenu-item-level-0');
$('.ubermenu li.ubermenu-item-level-0').removeClass('ubermenu-active');
target.parents('.ubermenu li.ubermenu-item-level-0').toggleClass('ubermenu-active');
});
HTML (mock):
<ul class="ubermenu">
<li class="ubermenu-item-level-0">
<a class="ubermenu-target">
<span class="ubermenu-target-title">Level 1</span>
</a>
<ul class="ubermenu-submenu">
<li class="ubermenu-item-level-1">
<a class="ubermenu-target">
<span class="ubermenu-target-title">Level 2</span>
</a>
</li>
<li class="ubermenu-item-level-1">
<a class="ubermenu-target">
<span class="ubermenu-target-title">Level 2</span>
</a>
<ul class="ubermenu-submenu">
<li class="ubermenu-item-level-2">
<a class="ubermenu-target">
<span class="ubermenu-target-title">Level 3</span>
</a>
</li>
</ul>
</li>
</ul>
<li class="ubermenu-item-level-0">
<a class="ubermenu-target">
<span class="ubermenu-target-title">Level 1</span>
</a>
</li>
</li>
</ul>
Right now if any of the sub elements are clicked the parent closes
Currently your target var is selecting all elements with class .ubermenu-item-level-0, so when you toggle the class you're toggling all parent elements. Your target var should be something relative to the element clicked, like var target = $(this).closest('.ubermenu-item-level-0');
So, your sample HTML isn't what I expected to see . . . specifically, your second <li class="ubermenu-item-level-0" . . . element is currently showing as a child under the first one, while your description makes it sound like they should be siblings.
For the sake of the solution I'm going to assume that those two lis are supposed to be siblings of each other and that somehow the code got mixed up. :)
So, here's how I would handle it . . .
var sFirstLevelMenuClass = ".ubermenu-item-level-0";
var sActiveMenuClass = "ubermenu-active";
var $firstLevelMenuOptions = $(".ubermenu").find(sFirstLevelMenuClass);
$firstLevelMenuOptions.children("a").children("span").on("click", function() {
$firstLevelMenuOptions.removeClass(sActiveMenuClass);
$(this).closest(sFirstLevelMenuClass).addClass(sActiveMenuClass);
});
Basically, I've simplified your logic and fixed one small issue that you had in your jQuery code.
Detailed Explanation
The issue was that when you used $('.ubermenu-item-level-0 span') as your selector for your change event. That translates to "any span element that is a descendant of a ubermenu-item-level-0 element". So, in addition to the spans that are directly under the ubermenu-item-level-0 list items, it was also picking up the ones under the ubermenu-item-level-1 and ubermenu-item-level-2 elements, since they are also descendants.
So, I changed your selector to $firstLevelMenuOptions.children("a").children("span") which translates to "all spans, that are direct children of an a, that is the direct child of an ubermenu-item-level-0 element" (Note: $firstLevelMenuOptions is set to equal $(".ubermenu").find(".ubermenu-active"); through the logic earlier in the code). This stops the selector from picking up the lower level spans.
Outside of that and trimming down some of your selectors to be more efficient, the only other thing that I changed was the flow of how the ubermenu-active class is manipulated. In my solution, there are two steps:
Remove ubermenu-active from ALL ubermenu-item-level-0 elements
Add ubermenu-active to the closest ubermenu-item-level-0 element to the span that was clicked (i.e., $(this))
That basically resets the list and then reselects the appropriate menu item to me active.
You can stop the event propagation:
event.stopPropagation()
Without seeing the full HTML, I was going to suggest trying this:
$('.ubermenu-item-level-0 span').on('click',function(e) {
e.stopPropagation();
var target = $('.ubermenu-item-level-0');
$('.ubermenu li.ubermenu-item-level-0').removeClass('ubermenu-active');
target.parents('.ubermenu li.ubermenu-item-level-0').toggleClass('ubermenu-active');
});
Related
<ul class="drillDownMenu l_drillDown" style="left: -498px;">
<li class="hasSubs">
<a id="RAL10" href="javascript:;">
<ul class="active">
<li class="hasSubs">
<li class="hasSubs">
<a id="AL101117" href="javascript:;">AR Invoices</a>
<ul class="displayed active">
<li>
<a id="FAL10111726" onclick="LoadQueryWindow(this,'104')">AR Invoices</a>
</li>
<li>
<a id="FAL10111727" onclick="LoadQueryWindow(this,'134')">All AR Invoices 1</a>
</li>
</ul>
</li>
I am trying to use the below driver statement,
driver.findElement(By.xpath("//*[contains(#id,'FAL10111727')]")).click();
But this selects the first element, I want to select the last element in the list.
Thanks
Try this xpath expression:
(//ul[ #class='drillDownMenu l_drillDown']//li)[last()]
it picks all li elements that are childs of the topmost ul, then picks the last element from the whole set.
As per the HTML you have shared,
To select the last 'li' which is changing dynamically for each run, All AR Invoices 1 in this case you can use :
driver.findElement(By.xpath("//ul[#class='displayed active']//following::li[last()]")).click();
But, I suppose the <li> tags won't receive a click and you have to invoke click() method on the inner <a> tag instead as follows :
driver.findElement(By.xpath("//ul[#class='displayed active']//following::li[last()]/a")).click();
//I tried using this which worked
driver.findElement(By.cssSelector("ul.displayed li:last-child a")).click();
I have a side menu that when clicked slides out to reveal a content panel. Based on the menu item clicked I obviously need different stuff to populate in the panel.
I wrote a function to operate the menu/panel and it partially works. However, I am trying to determine what to load based on event.target.id (as the function takes event) but it only has a value when I click very close to the edges of the linked square. When I click near the actual text which are h1 and h6 and have no id's it doesn't work.
Live demo (click near the edges of the 'Styles' square and then in the middle): http://jsfiddle.net/mANuD/
<div id="application-frame">
<div class="panel"></div>
<ul id="slide-out-menu">
<li>
<a href="#" class="item" id="styles-menu">
<h1>S</h1>
<h6>Styles</h6>
</a>
</li>
<li>
<a href="#" class="item" id="designers-menu">
<h1>D</h1>
<h6>Designers</h6>
</a>
</li>
<li>
<a href="#" class="item" id="code-menu">
<h1>C</h1>
<h6>Code</h6>
</a>
</li>
<li>
<a href="#" class="item" id="help-menu">
<h1>?</h1>
<h6>Help</h6>
</a>
</li>
</ul>
</div>
How can I fix/improve this so that it doesn't matter where in the linked area I click?
Change event.target.id to event.currentTarget.id or this.id.
The event.target is always the deepest element clicked, while event.currentTarget or this will point to the element to which the handler is bound, or to the element that the delegate selector matched.
It sounds like there's a border or padding on some of the descendant elements, and so event.target is a descendant of the element on which the handler is (effectively) hooked up.
Two options:
Use this.id to get the id of the element the handler was (effectively) bound to. This usually does what you want. Updated Fiddle
I don't think you need it in this situation, but the other handy tool in the toolkit for this is closest, which finds the first element matching a selector by looking at the element you give it, then its parent, then its parent, etc. So for instance, $(this).closest(".item").attr("id") or $(event.target).closest(".item").attr("id") (since the items you want have class item). Updated Fiddle But again, I believe #1 is what you want in this case.
I have this following hierarchy, and this is used at several places (so to add a class to them via jQuery is not feasable).
<li class="paginable">
<span id="step-1" class="done"></span>
</li>
<li class="paginable">
<span id="step-2" class="done"></span>
</li>
<li class="paginable">
<span id="step-3" class="done"></span>
</li>
<li class="paginable">
<span id="step-4" class="not-done"></span>
</li>
<li class="paginable">
<span id="step-5" class="not-done"></span>
</li>
On the basis of the class done on element span, I have to provide certain style to those span[id^="step-"] which are also having the class done.
But not including the last span with class done.
How can I exclude the last span with class done. The classes done and not-dont changes in order like a series of steps.
I've tried:
span[id^="step-"].done:not(-- with lots of combinations of last child on parent as well as child --)
But it won't work and I logically know why.
Any suggestions CSS ONLY? or should I go and add class everywhere it is switched using jQuery?
I don't think a css only solution is available.
Using jQuery
$('span.done[id^="step-"]').not(':last').css('color', 'red')
Demo: Fiddle
I have a side menu that when clicked slides out to reveal a content panel. Based on the menu item clicked I obviously need different stuff to populate in the panel.
I wrote a function to operate the menu/panel and it partially works. However, I am trying to determine what to load based on event.target.id (as the function takes event) but it only has a value when I click very close to the edges of the linked square. When I click near the actual text which are h1 and h6 and have no id's it doesn't work.
Live demo (click near the edges of the 'Styles' square and then in the middle): http://jsfiddle.net/mANuD/
<div id="application-frame">
<div class="panel"></div>
<ul id="slide-out-menu">
<li>
<a href="#" class="item" id="styles-menu">
<h1>S</h1>
<h6>Styles</h6>
</a>
</li>
<li>
<a href="#" class="item" id="designers-menu">
<h1>D</h1>
<h6>Designers</h6>
</a>
</li>
<li>
<a href="#" class="item" id="code-menu">
<h1>C</h1>
<h6>Code</h6>
</a>
</li>
<li>
<a href="#" class="item" id="help-menu">
<h1>?</h1>
<h6>Help</h6>
</a>
</li>
</ul>
</div>
How can I fix/improve this so that it doesn't matter where in the linked area I click?
Change event.target.id to event.currentTarget.id or this.id.
The event.target is always the deepest element clicked, while event.currentTarget or this will point to the element to which the handler is bound, or to the element that the delegate selector matched.
It sounds like there's a border or padding on some of the descendant elements, and so event.target is a descendant of the element on which the handler is (effectively) hooked up.
Two options:
Use this.id to get the id of the element the handler was (effectively) bound to. This usually does what you want. Updated Fiddle
I don't think you need it in this situation, but the other handy tool in the toolkit for this is closest, which finds the first element matching a selector by looking at the element you give it, then its parent, then its parent, etc. So for instance, $(this).closest(".item").attr("id") or $(event.target).closest(".item").attr("id") (since the items you want have class item). Updated Fiddle But again, I believe #1 is what you want in this case.
I am sliding content when the corresponding header is clicked using slidetoggle. Now I want to toggle between classes simultaneously.
I can use toggleclass and have all of the classes toggled irrespective of which one of the header is clicked, but I'm having trouble in toggling only the class corresponding to the headerclicked.
Here is my code:
<div class="Title ">
<a class="Expanded" href="#">Title1<span id="span1" class="ArrowDown"></span></a>
</div>
<ul class="Content">
<a href="#">
<li class="selected">hello1</li></a> <a href="#">
<li>hello2</li></a>
</ul>
<div class="Title">
<a class="Expanded" href="#">Title2<span id="span2" class="ArrowDown"></span> </a>
</div>
<ul class="Content">
<a href="#">
<li>hello3</li></a>
<a href="#">
<li>hij</li></a>
</ul>
Here is my script:
$(document).ready(function(){
$(".Title").click(function(){
$(this).next(".Content").slideToggle("slow");
$("#span1").toggleClass("ArrowUp", "ArrowDown");
});
});
I just put the id of the first span here, but I tried different things, but couldn't figure out what to do... I want the class of span toggled between ArrowUp and ArrowDown when the corresponding title is clicked (expanded or collapsed).
You can also use the power of jQuery chaining to write this in a single line like so.
$(this).find('span').toggleClass("ArrowUp", "ArrowDown").end()
.next(".Content").slideToggle("slow")
;
The two things to note in this are .find() (which gets the descendants of matched elements filtered by a selector) and .end() (which ends the most recent filtering operation in the current chain and returns the set of matched elements to its previous state.)
In the click callback function, make use of the this keyword, and combine it with the power of the .find() method.
example:
$('element').click(function() {
$(this).find('span').toggleClass('myclass');
});
$(this).find(' span').toggleClass("ArrowUp", "ArrowDown");