jQuery selector that excludes a subtree of the DOM - javascript

Is there a jQuery selector that will grab all elements of class A that are not descendants of class B?
Example:
<body>
<div class=report-value id=overview></div>
<div class=panels>
<div class=report-value id=sales></div>
<div class=report-value id=training></div>
<div class=report-value id=hr></div>
</div>
<div class=report-value id=summary></div>
</body>
For the above example, the need is to select all .report-value elements that are not descendants of the .panels element. The report values are computationally heavy and need to be calculated only when actually displayed.
Something like:
var elems = $('.report-value:excludeTree(.panels)');
which would return a jQuery object containing only #overview and #summary.
Performance is important for this web application.

You can use .not() filter out those elements
$('.report-value').not('.panels .report-value')
Demo: Fiddle

Try,
var elems = $('.report-value').filter(function(){
return $(this).closest('.panels').length ==0;
});
DEMO

var allpanels=$('body>.report-value');

$('body > .report-value')
or
$('.report-value').each(function(){
if(!$(this).parent().hasClass('.panels'))
{
//use query
}
});

Try this:
$('.report-value').each(function(){
if(!$(this).parent().hasClass('panels') && !$(this).parents().eq(1).hasClass('panels'))
{
console.log($(this));
}
});
It console only ur required divs

Related

Find the parents parent element using jquery

I have the HTML as follows. what i need is when someone clicks on the span element i want to find its parents parent element check some conditions. i used prev() method but it gives me only the near parent(parent2 here)
<div class="container">
<div class="contain">
<div id="parent1">
<div class="parent2">
<span> Click here</span>
</div>
</div>
</div>
</div>
var currentComponent = $(event.target).prev(); //here i get parent2
How can i find the parents parent element(in this case parent2). i am not very familiar with jquery so any help would be appreciated.
You can try .closest.
From the docs:
the .closest() method searches through these elements and their ancestors in the DOM tree and constructs a new jQuery object from the matching elements.
(...)
get the first element that matches the selector by testing the element itself and .
It traverses up through the element ancestors in the DOM and returns the first one that matches the selector you passed as an argument. So, in your example, you can do something like that:
$("span").on("click", function(e) {
var myParent = $(this).closest(".parent2");
var parentOfMyParent = $(this).closest(".parent1");
var contain = $(this).closest(".contain");
var containerAbove = $(this).closest(".container");
});
What you need is
var currentComponent = $(event.target).parent().parent()
To do it in a single call, you can use
var currentComponent = $(event.target).closest(".parent1")
Fiddle:
https://jsfiddle.net/c624re4o/
Code:
var grandParent = $(this).parent().parent();
Full Working Code
$(document).ready(function () {
$("span").click(function () {
var grandParent = $(this).parent().parent();
alert(grandParent.attr('id')); // Just for Testing
});
});
$(document).ready(function () {
$("span").click(function () {
var grandParent = $(this).parent().parent();
alert(grandParent.attr('id')); // Just for Testing
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="contain">
<div id="parent1">
<div class="parent2">
<span> Click here</span>
</div>
</div>
</div>
</div>
you can use .closest() or .parents() function with selector like .parents('#elementid')

Access elements inside a div outside of the current div

This is probably a very easy approach, however I haven't been able to figure it out.
My approach is to get all <img> elements that have the "expanded-image" class that are within the "img-preview" of my current "entry".
This is my html:
<div class="entry">
<div class="img-preview">
<img>
<img class="expanded-image" style="display:none;">
</div>
<div class="content">
[..]
[..]
<span class="more-text"></span>
[..]
[..]
</div>
</div>
And this is the JS I work with:
$('.content').each(function(event) {
$(this).find('span.more-text').click(function(event) {
// TODO
});
});
Firstly you don't need the each() at all as you can apply the click() event handler to all elements within a single selector.
To solve your issue you can use closest() to find the nearest parent .entry element to the clicked .more-text. From there you can find() all the .expanded-image elements. Try this:
$('.content span.more-text').click(function(event) {
var $imgs = $(this).closest('.entry').find('.img-preview .expanded-image');
// work with $imgs here...
});
$('.content').each(function(event) {
var $content = $(this);
$(this).find('span.more-text').click(function(event) {
$content.parent().find('.expanded-image'); // there you go
});
});
Use o combination of closest, prev and find
$('span.more-text').click(function(event) {
$(this).closest('.content').prev().find('.expanded-image');
});
You can use closest() to bubble up to find the parent given in the selector. Then from there you can navigate down to the required elements.
$(this).closest('.entry').find('.img-preview .expanded-image');
Also as Ron has suggested you dont have to loop and then bind the click events. You can simply do
$('.entry .content .more-text').click(function(){
$(this).closest('.entry').find('.img-preview .expanded-image');
})

CSS - Parent child selector not working

I have the following code:
.recipe
.ingredients
= f.simple_fields_for :ingredients do |ingredient|
= render 'ingredient_fields', f: ingredient
.row#links
.col-xs-12
= link_to_add_association "", f, :ingredients
%hr
I need to select the ingredients div using jquery in the format of $("#links")["closest"](".recipe > .ingredients") but this doesn't select anything.
It's frustrating though as $("#links")["closest"](".recipe > .row") will return the correct div.
Fiddle of what works and what I want: https://jsfiddle.net/yL6dr4s1/
According to jQuery documentation, closest method tries to find element matching the selector by testing the element itself and
traversing up through DOM.
It does not go through siblings of the element.
Based on your requirements, it seems like you want to traverse the tree for getting match in siblings. jQuery has siblings method to do that. So one solution would be to use siblings method like:
$("#links")["siblings"](".recipe > .ingredients")
Another soultion would be to get closest parent and then use children as answered by #mhodges
As for the query $("#links")["closest"](".recipe > .row"):
It works fine because closest method finds the match in the element itself.
Here is the example to showcase that:
$(document).ready(function() {
// Match found because it is parent
console.log($("#links")["closest"](".wrapper").length);
// No match found because element is sibling
console.log($("#links")["closest"](".row1").length);
// No match found because element is sibling
console.log($("#links")["closest"](".row3").length);
// Match found because it is element itself
console.log($("#links")["closest"](".row2").length);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="row1">
<span>Content1</span>
</div>
<div class="row2" id="links">
<span>Content2</span>
</div>
<div class="row3">
<span>Content3</span>
</div>
</div>
I am not sure of your requirements on using the exact selector/syntax you provided, but this selector works exactly how you want it to.
$(this).closest(".recipe").children(".ingredients").append('<br/><input type="text" value="Flour">');
Edit
This is the closest I could get:
$(this)["closest"](".recipe").children(".ingredients").append('<br/><input type="text" value="Flour">');
I don't think you can use the selectors in the way you propose.
As far as the DOM is concerned (and jQuery), the element defined by ingredient and the element defined by row are not related. You have to traverse up to the parent element, then back down to get to the child.
Here is a fiddle that hopefully demonstrates the issue.
If you can change it so that ingredient and row are both within the same parent div, you might have more luck with your test selector syntax.
When jQuery gets to buggy, doesn't have a certain option or just becomes to messy to use for a certain operation, it is good we also have access to good old plain javascript.
document.querySelector('#addToIngredients').addEventListener('click' , function(e) {
var recipe = getClosest(e.target,'recipe');
if (recipe) {
var ingred = recipe.querySelector('.ingredients');
ingred.innerHTML += '<br/><input type="text" value="Flour">';
}
});
function getClosest(elem,cls) {
var el = elem.parentNode;
while (el){
if (el.className.indexOf(cls) > -1) {
return el;
}
el = el.parentNode;
}
return false;
}
<div class="recipe">
<div class="ingredients">
<input type="text" value="Eggs"><br/>
<input type="text" value="Flour">
</div>
<div class="row">
<div class="col-xs-12">
Add to .ingredients
</div>
</div>
<hr/>
</div>
Of course they can be combined
$(function() {
$("#addToIngredients").on('click', function(e) {
var recipe = getClosest(e.target,'recipe');
if (recipe) {
var ingred = recipe.querySelector('.ingredients');
ingred.innerHTML += '<br/><input type="text" value="Flour">';
}
});
})

How select the selector from its method?

I need to change the text of '#foo #three' using 'this' to get the text of the div#one
The output I need is:
cat
dog
cat
Html:
<div id="foo">
<div id="one">cat</div>
<div id="two">dog</div>
<div id="three">mouse</div>
</div>
JS:
$("#foo #three").text($(this).parent().children().first().text());
I need this code dynamically
http://jsfiddle.net/Kodam/s466a31q/
Unless you are trying to do this dynamically, this is as simple as:
$('#three').text($('#one').text());
$("#three").text($('#foo').children().first().text());
Update: If you really want to use this to reference the match, would recommend to use each:
$("#foo #three").each(function(){ // this only matches #three
$(this).text($(this).parent().children().first().text());
})
Though this approach uses a kind of workaround, it works:
$jSelect = $("#foo #three");
$jSelect.text( function(){
var jParts = $jSelect.selector.split(" ");
return $(jParts[0]).find("div:first").text();
});
Fiddle
But I wouldn't recommend it as .selector is deprecated as of jQuery 1.7 and only maintained for supporting live() in the jQuery Migrate plugin.
For Reference: http://api.jquery.com/selector/
Update: And a similar approach without using .selector:
jSelect = ("#foo #three");
$(jSelect).text( function(){
var jParts = jSelect.split(" ");
return $(jParts[0]).find("div:first").text();
});
Fiddle
if you insist on using this, you can do it this way:
Fiddle Example
basically, since this only works inside a function context, you create a function that returns a string and put it inside the .text().
$(function () {
$("#foo #three").text(function () {
return $(this).parent().children().first().text();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
<div id="one">cat</div>
<div id="two">dog</div>
<div id="three">mouse</div>
</div>

How can I select an element which does not contain a certain child element?

<div class="test">
<div class="example"></div>
</div>
<div class="test">
</div>
How can I apply jQuery to an element with the class test only if it doesn't contain a child element with the class example?
$('.test:not(:has(.example))')
-or-
$('.test').not(':has(.example)')
Possibly
$('.test').filter(function() { return !$(this).children('.example').length; });
This filters out any elements that have any child that matches .example. If you want to filter based on descendants (not just children) that you can substitute .find for .children.
$(':not(.test:has(.example))').css('color', 'red');​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
http://jsfiddle.net/9fkz7y1g/
jQuery contains():
jQuery.contains(document.documentElement, document.body); // true
jQuery.contains(document.body, document.documentElement); // false
This problem seems ready-made for the filter function where you find all the .test objects and then when filtering retain only the ones that don't have .example in them:
$(".test").filter(function() {
return($(this).find(".example").length == 0);
});
You could use the method children with ".example" and test if it is empty
$('.test').each(function() {
if(!$(this).children().hasClass("example")){
//your code
}
});
Maybe like this? I haven't tested this...
if (!$('#yourDiv').children().hasClass("className")) {
//i.e. yourDivID' has no any children whose class name =>'className'
}

Categories