iterative dom tree traversal - javascript

I'm iterating little bits of jQuery for other people to use.
However, to get this to work I'm hoping to traverse up and then down the dom tree. This is so that the effects stay within the wrapping div, rather than affect the whole page. (I'm assuming multiple iterations of the same 'wrappingdivclass' and its content)
<div class="wrappingdivclass" >
<h4>series name</h4>
<div class="hoverheaders">
<p class="hoverheading"><!-- TEXT HERE (FOR INITIAL IMAGE) !-->image</p>
<p class="hoverheading1"><!-- IMAGE TWO TEXT !-->image</p>
<p class="hoverheading2"><!-- IMAGE THREE TEXT !-->image</p>
<p class="hoverheading3"><!-- IMAGE FOUR TEXT !-->image</p>
</div>
<div class="hovercontents">
<p class="hovercontent">athing</p>
<p class="hovercontent1">athing</p>
<p class="hovercontent2">athing</p>
<p class="hovercontent3">athing</p>
</div>
</div>
and the jquery (lives in an outside file)
these iterates for hoverheading1-3 and hovercontent1-3
example:
//does not work
jQuery(document).ready(function() {
jQuery(".hovercontent").show();
jQuery(".hoverheading").hover(function()
{
$(this).parent().children(".hovercontent").show()
$(this).parent().children(".hovercontent").siblings().hide();
});
});
// $(".hovercontent2").siblings().hide();
});
});
example 2:
//also does not work
jQuery(document).ready(function() {
jQuery(".hovercontent1").hide();
//toggle the componenet with class msg_body
jQuery(".hoverheading1").hover(function()
{
jQuery(this).closest(".hovercontent1").show();
jQuery(this).closest(".hovercontent1").siblings().hide();
});
});

You should be consistent.....either use the $ or use JQuery. You should avoid mixing them....
You might also benefit from using descendant selectors.
$(".wrappingdivclass > .hovercontents > .hovercontent2")
//Selects elements of class "hovercontent2" that have a parent element of "hovercontents", whose parent element is "wrappingdivclass"
$(".wrappingdivclass .hovercontent2")
//Selects elementss of class "hovercontent2" that are indirect descendants of "wrappingdivclass". Indirect means that it doesn't have to be direct child....it could be the grand-child, etc....

Related

How to select the last child inside the tree using jQuery?

Suppose I have such a structure:
<div id="content">
<div>
<span>
<b>
<i>
<u>
<span>Price</span>
</u>
</i>
</b>
</span>
</div>
</div>
In this case, the number of tags inside the div #content and which ones they don't know me. I only have access to the id content.
How do I get the selector to the latest span which contains the text Price?
p.s. lastChild method returns the last child within the selected selector, but not deeper!
Select all children of #content using * selector and use .filter() to filtering element. In callback filter elements hasn't any child.
$("#content *").filter(function(){
return $("*", this).length == 0;
});
// Or using ES6
$("#content *").filter((i,v) => $("*", v).length == 0);
var ele = $("#content *").filter((i,v) => $("*", v).length == 0);
console.log(ele[0].outerHTML);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="content">
<div>
<span>
<b>
<i>
<u>
<span>Price</span>
</u>
</i>
</b>
</span>
</div>
</div>
You can use .find():
https://api.jquery.com/find/
This will recursively look for your selector, so:
$('#content').find('span') will give you two spans, one for the first nested span and one for the second nested span. The downside is that if you have multiple spans you'll need to find the right one.
If you can put an identifier in the last one, say a class named 'target-class', than you know you'll find the right one:
$('#content').find('span.target-class');
First of all let's fix your syntax. You can't put an <span> directly within a <u>. You need a <li> node. Also you can't/shouldn't put block elements such as ul within inline elements (span, a, b, i...). And even <b> and <i> are not recommended, better use semantic markup such as <strong> or <em> instead.
Now your problem. I think you don't have to care about being the last node. If you know the text contained is "Price" you can look for it in the following way:
var selector = $('#content').find(":contains('Price')");
$(selector).addClass('highlighted');
.highlighted {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="content">
<div>
<u>
<li>
<span>Price</span>
</li>
</u>
</div>
</div>
If this solution does not fits your needs, to get the last node you have to get all of them an check if they have children or not. Once they don't, you've reached your target.
But I have to say that this is a solution you could have found in SO.
Select deepest child in jQuery
Jquery Way -
You could target all spans $() and target the latest span using slice() method.
$('#content span').slice(-1)[0];
Javascript way -
Find all spans using querySelectorAll(), You'd get a NodeArray, you can convert it to Array using Array.from() and slice() last item from it which is latest span.
Array.from(document.querySelectorAll('#content span')).slice(-1)[0]

targeting classes with jquery

Need to pass information from one class to another in a way that will validate. Current approach is a mess- works but does not validate.
I need to pass text inside a p tag to another element on the page. Right now i'm using a tag attributes to pass this info along. Super messy.
<div class="element-item">
<div class="text-panel">
<div class="text-cell">
<a class="ajax" href="ajax/bkdesks.html" id="Brooklyn Desks" dir="BROOKLYN, NY">
<p class="link"><img src="img/chainlink.png" width="60" height="60" alt="link" alt=""/></p>
<p class="name">Brooklyn Desks</p>
<p class="dir">Brooklyn, NY</p>
</a>
</div>
</div>
And then jQuery:
$('.ajax').click(function(e) {
e.preventDefault();
$('#projects-head .titlehead').text($(this).attr('id'));
$('#projects-head .subhead').text($(this).attr('dir'));
$('#project').load($(this).attr('href'));
});
titlehead and subhead are the other elements on the page whose content is being replaced. I would much rather grab the contents of the p tags below than put everything in the a id & dir. But i cant figure out the jquery to target them.
The p.name and p.dir elements are descendant elements of the clicked .ajax element so you can use .find()
$('.ajax').click(function (e) {
e.preventDefault();var $this = $(this);
$('#projects-head .titlehead').text($(this).find('.name').html());
$('#projects-head .subhead').text($(this).find('.dir').html());
$('#project').load($(this).attr('href'));
});

jQuery selector to ignore specified element

Consider this DOM :
<div id="div1">
<div class="no-select-inside">
<p>Don't select me</p>
</div>
<div>
<p>Select me</p>
<div><p>Select me too</p></div>
</div>
<div>
<p>Select me</p>
<div><p>Select me too</p></div>
</div>
<footer class="no-select-inside">
<p>Don't select me</p>
<div><p>Not me</p></div>
</footer>
<section>
<p>Select me</p>
<div><p>Select me too</p></div>
</section>
</div>
I want a fast and reliable jquery (or bare DOM) selector to select those p tags that not inside 'no-select-inside' class
Everything is dynamic, but I can assign an attribute to not selectable DOM element.
Edit
The real test case isn't a class selector (maybe a complex attribute selector, ...)
Everything is dynamic and could be too deep nested (100 down to DOM tree under a no-select-inside there is p that has a no-select-inside parent and with all the answer even those elements are selected)
I have all no-select-inside cached (Backbone's $el and can be cached in an array for performance) but real problem is selecting those elements in a fast way (20ms in chrome is too slow!).
The general-purpose solution would be to filter out those that have a .no-select-inside ancestor, for example:
$("p")
.filter(function() { return !$(this).closest(".no-select-inside").length;})
// and now do what needs to be done
This should be reasonably efficient because it only goes over the whole document just once.
Try using .not() or :not() to filter out the p elements inside no-select-inside
$('#div1 p').not('.no-select-inside p')
$('#div1 p:not(.no-select-inside p)')
Try this:
$('div:not(.no-select-inside) p')
You can use .not as the working example is here
$(document).ready(function(){
var abc = $('#div1').find("p").not('.no-select-inside p');
$(abc).each(function(e){
alert($(this).html());
});
});
http://jsfiddle.net/8F7Kc/14/

JQuery. Remove a previous sibling in the DOM tree

I have the next code dynamically created using JQuery. Theere are multiple row class divs placed one under the other.
<div class="row">
....
</div>
<div class="row">
<div class="line_type"></div>
<div class="download_value"></div>
<div class="flag"></div>
<div class="email"></div>
<div class="prize"></div>
</div>
<div class="row">
....
</div>
After i create these divs I have a "pointer" to a specific div which is of class row. In JQuery, how do i make it so I go down the DOM tree, until i reach the div of class line_type and download_value and remove them both, and also I'd like to go one more node down, at the div of type email and change some of it's CSS attributes.
I was not able to find anything on the web, maybe it's cause i'm a noob at these still.
I have a "pointer" to a specific div which is of class row ->
Assuming that you have the this object of the corresponding div with class row.. then you can use .find to get the line_type and download_value inside that div.
$(this).find('.line_type').remove();
$(this).find('.download_value').remove();
Then you can use the same .find to get the div with class email and access the .css
$(this).find('.email').css(/* You code*/);
Assuming row_pointer points to the row in question:
$('.line_type, .download_value', row_pointer).remove();
$('.email', row_pointer).css(...);
check this out
$('div.row').bind('click', function() {
$this = $(this);
$('div.line_type, div.download_value', $this).remove();
$('div.email', $this).css('background-color', 'red');
});
http://jsfiddle.net/YvyE3/

Easiest way to get element parent

Suppose i have this structure of elements:
<div class="parent">
<div class="something1">
<div class="something2">
<div class="something3">
<div class="something4"></div>
</div>
</div>
</div>
</div>
And code like this:
$(".something4").click(function(){
//i could do it like this...
$(this).parent().parent().parent().parent().parent();
});
But that seems to be stupid, is there a better way to do this?
also i can't just say $(.parent) because there are many divs like this with class parent in my page.
Use .closest(selector). This gets the first element that matches the selector, beginning at the current element and progressing up through the DOM tree.
$('.something4').click(function() {
$(this).closest('.parent');
});
Use .closest():
$('.something4').click(function() {
$(this).closest('.parent');
});
I think you should try this
$(this).parents(".parent");
But I don't know where on the page are the other divs with this class :)
You could always use .parentNode (standard JavaScript). It's generally a bad idea to use class names that coincide with function/variable names from the library you're using (this goes for any language). Making your class names more unique is a better approach (for instance, "scparent" instead of "parent", if the name of your application was "Super Calculator" or something). This avoids conflicts such as the one you're describing.
I would caution using .closest(), simply because you may create a function like this:
function getParentElem() {
return $(this).closest('div');
}
And it would grab the parent div's in your code just fine, but if down the road you add a table for displaying data, and you run the function through a child element of the table, you will have to create another implementation that selects the table element, because that's what you now want:
<div id="tableParent">
<table id="dataTable">
<tr id="target1">
<td>Some data.</td>
</tr>
</table>
</div>
By using your function getParentElem() on the tr element, you'll end up grabbing the div with id="tableParent", rather than the actual parent, which is the table element. So, unless you've delineated your parent classes appropriately all the way through your code (which can be a pain and isn't always efficient), you may run into problems. Especially if at any point you're creating elements programmatically, or reading in data from another 3rd-party library or script.
Not saying it's not good to use .closest()... just pointing out a possible "gotcha".
i would suggest adding to the div parent an id like 'parent_1' etc. and in every son you keep the id in the rel attr
<div id="parent_1" class="parent">
<div rel="1" class="something1">
<div rel="1" class="something2">
<div rel="1" class="something3">
<div rel="1" class="something4"></div>
</div>
</div>
</div>
</div>
$(".something4").click(function(){
//i could do it like this...
$('#parent_' + $(this).attr('rel'));
});

Categories

Resources