What's the jquery selector for excluding nested descendents? - javascript

Per my SO question here, which has turned to jquery to solve this, but which may be worked back into YUI if I get my thinking straight, I need a selector to exclude descendents.
The solution proposed says something like this:
$( '.revealer:not(.revealer > .revealer)' );
To fit more accurately with my situation, because I have multiple HTML chunks to perform the same test on, I have updated it be:
$( '#_revealerEl_0 .handle:not(#_revealerEl_0 .reveal .handle)' );
The HTML its selecting on (image there are numerous copies of this same chunk on a page, each needing to be treated alone - an id attribute is assigned to each 'revealer'):
<div class="revealer" id="#_revealerEl_0">
<div class="hotspot">
<a class="handle" href="javascript:;">A</a>
<div class="reveal">
<p>Content A.</p>
</div>
<div class="reveal">
<p>Content B.</p>
<!-- nested revealer -->
<div class="revealer">
<div class="hotspot">
<a class="handle" href="javascript:;">A</a>
<div class="reveal">
<p>Sub-content A.</p>
</div>
<div class="reveal">
<p>Sub-content B.</p>
</div>
</div>
</div>
</div>
</div>
</div>
In a nutshell: I need to target 'top level' handles within a 'hotspot', per revealer - and no nested descendents with the same class names.
thanks,
d
EDIT:
It's also quite important that I don't start relying on descendant properties like parentNode, childNode[x], nextSibling, etc ... because currently this module is quite flexible in that its 'reveal' and 'handle' elements can reside within other markup and still be targeted - so long as they're found inside a 'hotspot'.

I don't know which is your #_revealerEl_0 element, but if it's your top-level .revealer, can't you just do this?
$('#_revealerEl_0 > .hotspot > .handle')
Or if the top-level .revealer is itself a descendant of #_revealerEl_0, then this works:
$('#_revealerEl_0 > .revealer > .hotspot > .handle')
The basic premise here is that you chain multiple > child combinators.

This works for me using jQuery:
$('.revealer:first > .hotspot > .reveal')
Given the first revealer, find any hotspots that are DIRECT children, and find any DIRECT reveal items within.
So, to assign handlers to your 'handles':
$('.handle').click(function(){
$(this).closest('.hotspot > .reveal').show();
});
The above translates to:
For any given handle, assign a click event function to the element
When a handle is clicked, find its closest parent hotspot
From the hotspot, find any reveal elements that are direct children of the hotspot
Show those elements if they were hidden with display: none.

Try this:
obj = $('.revealer[id*="revealerEl"]');
//this will give you what you are after
result = $("> .hotspot > .handle",obj)
//if you want to see them in red
$("> .hotspot > .handle",obj).css('color','red');
//or assign a click to it
$("> .hotspot > .handle",obj).click(function(){
//blah ....
})

Related

Trying to traverse the DOM so unique video will play when certain div is clicked

So, I have a requirement for dynamically generated content blocks on a page. These blocks have a thumbnail and when it is clicked, it should open a modal, and display an unique overlay window, as well as as the unique associated video.
I am trying to write some generic JavaScript that will traverse the DOM tree properly, so that when any particular thumbnail is clicked, a modal, the associated overlay, and the associated video will open.
Here is an example of what I have now (there are many of these, dynamically added):
<div class="block">
<div class="thumbnail">
//Thumbnail image
</div>
<p>Video Description</p>
<div class="window hide">
<div class="video hide">
//Video content
</div>
</div>
</div>
<div id="modal" class="hide"></div>
and after attempting to do a bunch of different things, I ended up trying to do something like this for the JavaScript, which doesn't work:
$(".thumbnail").on("click",function(){
$("#modal").removeClass("hide").addClass("show");
$(this).closest(".window").removeClass("hide").addClass("show");
$(this).closest(".video").removeClass("hide").addClass("show");
});
CSS is very basic:
.hide { display: none; }
.show { display: block; }
Trying to make the click function generic as possible so it would work on any .thumbnail that was clicked. I've also interchanged find(".window") and children(".window") but nothing happens. Any ideas on what I'm doing wrong? Thanks!
Depending on what you actually want your classes to be, I'd use this code:
$(".thumbnail").on("click", function () {
var $block = $(this).closest(".block");
$block.find(".window, .video").add("#modal").removeClass("hide").addClass("show");
});
DEMO: http://jsfiddle.net/gLMSF/ (using different, yet similar code)
It actually finds the right elements, based on the clicked .thumbnail. It finds its containing .block element, then looks at its descendants to find the .window and .video elements.
If you actually want to include . in your attributes, you need to escape them for jQuery selection.
As for styling, you should probably just have the styling be display: block; by default, and then toggle the hide class. It's less work, and makes more sense logically.
You have a huge issue with your class names in HTML:
<div class=".block">
it should be
<div class="block">
Your modal is the only one that has the class properly named. Your DOM traversals will not work because they are looking for "block" but it's called ".block"
So fix it all to this and you should find more success:
<div class="block">
<div class="thumbnail">
//Thumbnail image
</div>
<p>Video Description</p>
<div class="window hide">
<div class="video hide">
//Video content
</div>
</div>
</div>
<div id="modal" class="hide"></div>
Your code won't work because your selectors have periods (.) in your classes if that's actually what you want, you should try it like this:
$(".\\.thumbnail").on("click",function(){
$("#modal").removeClass("hide").addClass("show");
$(this).closest("\\.window").removeClass("hide").addClass("show");
$(this).closest("\\.video").removeClass("hide").addClass("show");
});
Otherwise just try removing the periods from the classes...
Also, you're using .closest() incorrectly, as it looks up through ancestors in the DOM tree...
You should change your code to:
$(".\\.thumbnail").on("click",function(){
$(this).next("\\.window").children(".video")
.addBack().add("#modal").removeClass("hide").addClass("show");
});

Need a more elegant way of finding an element in the dom tree with jQuery

I have a few elements flying around in an element that need to be altered when the window finishes loading ($(window).load...)
When the script loads, I've been struggling to find a more elegant way of finding a string.
Noticeably below, you can also see the rampant re-use of parent and next operators...
I've tried closest but it only goes up the dom tree once (from what I understand) and parents has never really worked for me, but I could be using it wrong.
Ex.
$(window).load( function(){
if($(".postmetadata:contains('Vancity Buzz')").length){
$(this).parent().parent().next().next().next().next('.articleImageThumb img').hide();
}
});
HTML output this runs through looks like this:
<div class="boxy">
<div class="read">
<div class="postmetadata">Vancity Buzz</div>
<div class="articleTitle"></div>
</div>
<div class="rightCtrls"></div>
<div class="initialPostLoad"></div>
<div class="ajaxBoxLoadSource"></div>
<div class="articleImageThumb">
<a href="#">
<img src="image.png" class="attachment-large wp-post-image" alt=""/>
</a>
</div>
</div>
I think you want to do this:
$(".postmetadata:contains('Vancity Buzz')")
.closest('.read') //Closest will get you to the parent with class .read
.siblings('.articleImageThumb').hide(); //this will get you all the siblings with class articleImageThumb
this refers to window there not the element you are checking in the if condition.
Fiddle
I don't know if your intention is to have the empty anchor tag just by hiding the image. if so just add a find to it.
You can just do this
$('.articleImageThumb img').toggle($(".postmetadata:contains('Vancity Buzz')").length)
If there are multiple divs and you do need to traverse then there are multiple ways
$(".boxy:has(.postmetadata:contains('Vancity Buzz'))").find('.articleImageThumb img').hide()
or
$('.postmetadata:contains("Vancity Buzz")').closest('.boxy').find('.articleImageThumb img').hide()
or
$(".boxy:has(.postmetadata:contains('Vancity Buzz')) .articleImageThumb img").hide()
Have you looked into parents http://api.jquery.com/parents/ you can pass a selector like so:
$(this).parents('.boxy').find(".articleImageThumb")
Careful though, If there is a parent boxy to that boxy, parents() will return it and thus you find multiple .articleImageThumb.

How to find first parent element in jquery

Conside below html -
<div class="container1">
<div class="container2">
<div class="container3">
<div class="container4">
<div class="element">
...
</div>
</div>
</div>
</div>
if I want to get <div class="element"> element and I have reference to the container1. In jquery what I do is,
$(".container1").find(".element")
instead of -
$(".container1").children().children().children().find(".element")
This is process to find any child element when I have reference to any of the parent element. But instead when I have reference to a child element and want to get parent element then every time I have to go one level up -
$(".element").parent().parent().parent().parent()
and I can't do like this -
$(".element").findParent()
I have not come across any method like findParent() in jquery. Is there which I am not aware of? Or is it not there for some reason?
$(".element").parents();
will give all parents of .element(including html and body)
DEMO
To find any specific parent, suppose container1 then
$('.element').parents('.container1')
DEMO
jQuery .parents() generally find all parents, but if you passed a selector then it will search for that.
just use
$(".element").closest('#container1');
if no ancestor with that id is found then
$(".element").closest('#container1').length will be 0
To get the first parent personally I use the following construction:
var count_parents = $(".element").parents().length;
$(".element").parents().eq(count_parents - 1);
Hope, it will be helpful for someone.

from parent to child without traversing the full path

My divs are nested like this.
<div id="top">
<div class="child1">
<div class="child-child">
<div class="child-child-child">
</div>
</div>
</div>
<div class="child2">
<div class="child-child">
<div class="child-child-child">
</div>
</div>
</div>
</div>
Right now I'm going from #top to .child-child-child by doing this.
$('#top').children('.child1')
.children('.child-child')
.children('.child-child-child');
Do I have to specify the full path like this? I want to omit the middle divs if there's a syntax that would let me do that. But I probably still need to specify whether I want to go through .child1 or .child2.
You do need to specify which path to take, but you could make it a little shorter:
$('#top > .child1').find('.child-child-child');
This will give you the '.child-child-child' that is a descendant of .child1.
Or you could write it like this, using only selectors:
$('#top > .child1 .child-child-child');
Or this, using only traversal methods:
$('#top').children('child1').find('.child-child-child');
You can just use a descendant selector (a space) to find the child anywhere beneath (as .find() does), like this:
$('#top .child-child-child');
Or, a bit more specific:
$('#top > .child1 .child-child-child');
To simplify this, you can use the selector:
$('#top .child1 .child-child-child');
This selector says "an element with a class of .child-child-child that is inside an element with a class of .child1 that's inside an element with an id of top".

Telling jQuery which (unique) div to do an action on

My plan is to have lots of boxes (an undefined amount). When show box is clicked under a box, it shows that particular box.
I have some unique divs in my html. The div is made unique by:
<div id="box-<%=box.id%>"></div>
In my application.js, I have
$('.show-box > a').click(function(){
$('#box').show();
});
I obviously need to have the box-id in the $('#box').show(); part but I'm unsure how to do that...
EDIT: adding more information
<div class="show-box">
Show
</div>
<div class="box" id="box-<%= box.id %>"></div>
The class is for styling.
Just to add, I know that the javascript link should link to an actual link. I'll fix that later.
You would use this inside the handler to refer to the specific .show-box > a that was clicked.
So it depends on what the relationship is between that and the box element you want to display.
When you say under, if that means that it is a sibling to the .show-box element, you can use .parent() to traverse up from the <a>, then use .prev() to traverse back to the box.
$('.show-box > a').click(function() {
// "this" refers to the <a> that was clicked.
$(this).parent().prev().show();
});
Ultimately, the correct solution depends on your actual HTML markup. If you provide that in your question, it would be helpful.
You could select by ID if you want, but it is often not necessary.
On easy way would be to name your box ids after you a ids, or write another attribute into the a. For example if your a tag's ID was "anchor1", assign the corresponding div an id of "box-anchor1". Then, reference it like this:
$('.show-box > a').click(function(){
$('#box' + this.attr('id')).show();
});
If the box and the link that shows it are logically related, you can skip the whole unique ID business by using the following:
HTML
<div class="container">
<div class="box">
<!-- stuff in the box -->
</div>
Show
</div>
jQuery
$("div.container a").click(function() {
$(this).prev().show(); // prev() will get the div.box element.
});
On the other hand, if they are not related structurally, you can use the fragment part of the URL to reference the box ID:
HTML
<div>
<div class="box" id="box-1">...</div>
<div class="box" id="box-2">...</div>
</div>
<div>
<a class="boxtoggler" href="#box-1">Show Box 1</a>
<a class="boxtoggler" href="#box-2">Show Box 2</a>
</div>
jQuery
$("a.boxtoggler").click(function() {
var boxId = $(this).attr("href");
$(boxId).show();
});
Note how we're abusing the fact that the fragment section of a URL is preceded by a # character to make it into a css ID ;)
Not sure I understood your question, but if you want to show the clicked box:
$('.show-box > a').click(function(){
$(this).parents('.show-box').show();
});

Categories