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/
Related
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]
I am bulk deleting all div elements with the id that starts with leg-:
$('div[id^="leg-"]').remove();
I also want to delete <hr> element that comes after each div:
<div id="leg-1">
...
</div>
<hr>
There is no event fired that's why, I am unable to select the element like this:
$(this).next();
How can I do this?
You can cache the selection made by jQuery in an intermediate variable like following:
var selection = $('div[id^="leg-"]');
selection.next().remove();
selection.remove();
Like in the $(this) methodology you wanted to use, the variable selection now contains a reference to all the divs you want to remove. Calling next() on that selection returns the immediate sibling, thus the hr you want to delete, for each of those div.
In general: Wherever you need the same selection in jQuery twice, consider saving it to a variable to speed up your scripts and reduce DOM querying to a minimum.
You can select next hr of div using .next() and use .addBack() to adding div to jquery selector.
$("div[id^=leg-]").next().addBack().remove();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="leg-1">leg-1 text</div>
<hr>
<div>text</div>
<div id="leg-2">leg-2 text</div>
<hr>
<div>text2</div>
Try this First remove next <hr> element the remove selection element
$(document).ready(function(){
var selection = $('div[id^="leg-"]');
selection.next('hr').remove();
selection.remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="leg-1">
1
</div>
<hr>
<div id="leg-2">
2
</div>
<hr>
<div id="">
3 not leg
</div>
<hr>
You could remove the hr by combining the jQuery next and remove functions in this way:
$(function() {
$('div[id^="leg-"]').each(function(i, v) {
$(v).next("hr").remove();
$(v).remove();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="leg-1">#leg-1</div>
<hr>
<div id="not-leg-1">#not-leg</div>
<hr>
<div id="leg-2">#leg-2</div>
<hr>
You are not removing the next element only selecting it.
Please to also add: $(this).next().remove(); before removing the div element.
You can use jQuery.each(): https://jsfiddle.net/cdzswdrk/1/
// when document ready
$('div[id^="leg-"]').each(function(){
var $this= $(this);
$this.next().remove();
$this.remove();
});
I am trying to use AngularJS to grab the element by tag name.
For example,
angular.element(document.querySelector('h1')).css('color', 'green');
element in HTML:
<div>
<h1>Title 1</h1>
</div>
<div>
<h1>Title 2</h1>
</div>
It works only for the first element but not the second one. I am not sure the reason for it. Can anyone help me about it? Thanks a lot!
As #Tushar mentioned, the best way to handle this is with ng-class. Let Angular do the DOM manipulation for you
Your CSS
.someclass{
color: green
}
Your HTML
<div ng-class="{'someclass': obj.value == 'somevalue'}">
<h1>Title 1</h1>
</div>
<div>
<h1>Title 2</h1>
</div>
After 'someclass', in your controller, you can insert whatever expression makes the most sense. When your expression evaluates to true, the 'someclass' will be applied to your Div.
The querySelector() method returns the first element that matches a specified CSS selector(s) in the document.
The querySelectorAll() method returns all elements in the document that matches a specified CSS selector(s), as a static NodeList object.
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....
I have a div that contains four paragraph tags. When the page is loaded, I wanted to have the first two paragraphs to be shown then have the follow paragraph elements be hidden, but I have no idea how to do this. For simplicity I set the event to a button versus a document ready event in the jsfiddle example below.
http://jsfiddle.net/zTCFe/4/
<div id="div">
<p>1 keep me shown</p>
<p>2 keep me shown</p>
<p>3 hide me</p>
<p>4 hide me</p>
</div>
<input type="button" value="press" id="button"/>
<script>
$('#button').click(function () {
$('#div').children().hide();
});
</script>
You were almost there:
$('#div').children(':gt(1)').hide();
More on the :gt selector.
http://jsfiddle.net/gromer/Tdue6/1/
Use the :gt() selector to select them
As an alternative, you can also use .slice()
$('#div').children().slice(2).hide();
http://api.jquery.com/slice/
You can use the :gt() selector:
$("#div p:gt(1)").hide();
Or, you can also use .slice() to select specific elements from the jQuery object's DOM array:
$("#div p").slice(2).hide();
You could also just use CSS for this
li:nth-child(-1n+2) {
background: yellow;
}