How to recursively select all children under an element Javascript - javascript

I need a function that recursively selects all child elements but wont select elements (and those elements children) if they have the "foo" attribute.
<section>
<div>
<span foo>
<input>
</span>
</div>
<p>
<img>
</p>
</section>
//should return [section, div, p, img]
I need raw Javascript please
edit:
I tried something like this:
$tag.querySelectorAll(":not([foo])")
but querySelectorAll(":not([foo])") will still return the children of the unselected element.

You can use element.querySelectorAll() with the :not modifier here, together with the [attr] selector:
var nonFooElements = parentElement.querySelectorAll("*:not([foo])");
Be aware that this sort of call will be moderately expensive because the selector doesn't begin with an id or a classname, so don't do huge amounts of it.
I adapted this answer from this one: https://stackoverflow.com/a/21975970/5009210

Related

How to get all Child Elements with specific attribute in JavaScript

I have an object that was retrieved from this expression:
const element = document.querySelector("...my selector...");
I need to get all child elements that have certain attributes, The only way I know to get all children is by:
const children = Array.from(element.childNodes);
but now each child in children is not an element, rather a node, hence, I cannot use getAttribute('') on them;
How do I "cast" a Node to an Element?, Or is there a better way to do this?
How do I "cast" a Node to an Element?
You can't.
Elements are a subset of Nodes.
If it isn't an Element already, then you can't turn it into one.
Consider:
<div>Hello, <strong>World</strong></div>
You have two child nodes. The text node "Hello, " and the strong element node.
It doesn't make sense to treat "Hello, " as an element.
Consider using children instead of childNodes. It fetches only element children.
I need to get all child elements that have certain attributes
In that case, you're probably better off just using a selector which gets you that in the first place. You'll need a child combinator and an attribute selector in addition to your existing selector. Then you'll need to use All to get more than one result.:
document.querySelectorAll("...my selector... > [someAttribute]"
You said you want to select all children with a specific attribute. So select them with querySelectorAll using an attribute selector.
var elems = document.querySelectorAll("#theParentSelector > [theChildsAttribute]")
console.log(elems.length)
Array.from(elems).forEach( function (el) {
console.log(el.getAttribute("theChildsAttribute"))
});
<div id="theParentSelector">
<div theChildsAttribute="1">Foo 1</div>
<div>Bar</div>
<div theChildsAttribute="2">Foo 2</div>
<div theChildsAttribute="3">Foo 3</div>
</div>
You'd use children to gain access to all HTML based nodes:
document.querySelector("...my selector...").children

How to replace all id from href?

I have the following markup
<div class = "general">
<div id ="custom"></div>
</div>
How to change id = "custom" in all <div> with class="general" from href on page using jQuery?
You can try this:
$("div.general").each(function() {
$(this).children("div#custom").text($(this).children("a").attr("href"));
});
If I understand you correctly, you want to iterate through all div.generals, and change the text of each child div#custom to the href of the child a.
See a working example on JSfiddle.
Also, another tip is to avoid using multiple elements with the same id. In your code you have a <div> with id="custom". You also say that the div.general appears multiple times — therefore, the id "custom" will appear multiple times. This is bad practice. I suggest that you change id to class.
You need to loop through all div.general and replace the id attribute of div#custom to whatever is there as the anchors href property. The following code will work:
$(".general").each(function(){
$(this).find("#custom").attr("id", $(this).find("a").attr("href").replace("#", ""));
})
Here the .find() will dig out elements from any depth inside the parent. If you are sure about the DOM position of the elements, you can change the .find() to .children()

Is there a method in jQuery that will traverse up the dom tree from an element and check selectors before its parent element

For example:
<div class="mainWrapper">
<div class="FirstLayer">
<input class="foo" value="foo" />
</div>
<div class="SecondLayer">
<div class="thirdLayer">
<input class="fee" />
</div>
</div>
</div>
Lets say I have the input.fee as a jQuery object and I also need to get the value of input.foo.
Now I know I can use a multitude of approaches such as $(this).parents(':eq(2)').find('.foo') but I want to use this one method on layouts which will have varying levels and numbers of nodes.
So I am wondering if there is a method which will simply start from .fee and just keep going up until it finds the first matching element, .prevAll() does not appear to do this. There are many .foo and .fee elements and I need specifically the first one above the .fee in context.
How about this:
$('input.fee').closest(':has("input.foo")')
.find('input.foo').val();
Here's JS Fiddle to play with. )
UPDATE: Kudos to #VisioN - of course, parents:first is well replaced by closest.
This will select the previous input.foo
// self might have siblings that are input.foo so include in selection
$( $("input.fee").parentsUntil(":has(input.foo)").andSelf()
// if input.off is sibling of input.fee then nothing will
// be returned from parentsUntil. This is the only time input.fee
// will be selected by last(). Reverse makes sure self is at index 0
.get().reverse() )
// last => closest element
.last()
//fetch siblings that contain or are input.foo elements
.prevAll(":has(input.foo), input.foo")
// first is closest
.first()
// return jQuery object with all descendants
.find("*")
// include Self in case it is an input.foo element
.andSelf()
.filter("input.foo")
// return value of first matching element
.val()
jQuery.closest() takes selector and does exactly what you need - finds the first matching element that is parent of something. There's also jQuery.parents() that does take a selector to filter element ancestors. Use those combined with find method and you're set.
$('input.fee').closest('.mainWrapper").find('.foo') does the trick, doesn't it?

Is Id necessary in applying jquery functions?

Suppose I have two p tags in the document. I want to call two different effects using jQuery when onMouseOver event happens. Is it necessary that these two p tags be given Ids. Can't it be achieved without giving Ids to these tags ?
You don't have to give anything an id, however it is the best way to uniquely identify an element.
You can instead idenfity by class:
$(".myClass")
By attribute:
$("[src='image.jpg']")
By position in parent:
$("p:eq(2)")
A full list of selectors is available in the documentation
$('p:first'); // first p tag
$('p:last'); // last p tag
$('p').eq(1); // exactly the second p tag
There are several ways to select an element / elements:
$('.classname')
$('#id')
$('tagname')
$('[attr="value"]')
etc
although jQuery allows you to write faster and easier scripts, but unfortunately it makes you never understand the real JavaScript.
$("*") //selects all elements.
$(":animated") //selects all elements that are currently animated.
$(":button") //selects all button elements and input elements with type="button".
$(":odd") //selects even elements.
$(":odd") //selects odd elements.$("p") selects all <p> elements.
$("p.intro") //selects all <p> elements with class="intro".
$("p#intro") //selects the first <p> elements with id="intro".
$(this) //Current HTML element
$("p#intro:first") //The first <p> element with id="intro"
$("p:eq(2)") // The third <p> element in the DOM
$(".intro") //All elements with class="intro"
$("#intro") //The first element with id="intro"
$("ul li:first") //The first <li> element of the first <ul>
$("ul li:first-child") //The first <li> element of every <ul>
$("[href]") //All elements with an href attribute
$("[href$='.jpg']") //All elements with an href attribute that ends with ".jpg"
$("[href='#']") //All elements with an href value equal to "#"
$("[href!='#']") //All elements with an href value NOT equal to "#"
$("div#intro .head") //All elements with class="head" inside a <div> element with id="intro"
jQuery – Select element cheat sheet

jQuery looping through .children of .children

I've been looking over previously asked questions and can't seem to find a solution for my scenario...
I'd like to be able to loop through all children and children of children, etc...
the markup from design looks similar to this
<div>
<div>
<label></label>
</div>
<div>
<label></label>
</div>
<div>
<label></label>
</div>
</div>
I'd like to be able to select all labels within a specific div, regardless of their direct parent.
I'd like to be able to select all labels within a specific div, regardless of their direct parent.
It's just CSS selector notation. Assuming that <div> has an ID of myDiv:
$('#myDiv label').each(function ()
{
// do stuff
});
You do not need to keep stepping down through children in order to find labels within a specific div. This will do the job for you:
$('#idOfDiv label')
$('div label') will select any descendant of that div, regardless of depth. If you want it to be children or children of children, you can select like $('div > label, div > * > label')
Use the find function (instead of children) like so: $('#container').find('label')
$('div:first').find('label') will give you each label element
To select all labels:
$('label').something();
To select all labels contained in a div:
$('label', 'div').something();

Categories