How to get all Child Elements with specific attribute in JavaScript - 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

Related

Is it valid to add the same element as a child to two different parent elements in jQuery?

Suppose I have some HTML as so,
<div id="first"></div>
<div id="second"></div>
and using JavaScript and JQuery I attempt to do the following
var $child = $("<span id='child'>Hello</span>");
$("#first").append($child);
$("#second").append($child);
Will I have two copies of the child node, or will I have two references to the same child node?
Update
I realise that my example creation of a child element is a bit wrong. Perhaps
var $child = $("<span/>").text("Hello");
is a bit more correct.
Child appended in the #first element will get moved to #second element leaving #first element empty. You can use clone() to insert a copy of the child element.
However, there should not be multiple elements with the same ID in DOM, so please change ID to Class for the child element

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()

What is the best practice to get a child of an element in HTML?

Something like get an variable out of class.
ParentElement.someId.someId..
If i have something like that in css:
#someId #aaa #bbb
{
...
}
#someOtherId #aaa #bbb
{
...
}
and i want to get only the element under "#someId".
Something like
getElementById("someId aaa bbb");
would be great, unfortunately this one doesn't work.
Any ideas?
If you have given an id to the element, you can say
document.getElementById(childId)
Id must be unique in the document.
In your scenario, what I think you are having element with same Id at multiple places. Either you can user class instead of id.
I assume you want to get the element in javascript, or what do you mean by "getting" in HTML?
<div id="box">
<div>Child element</div>
<div>Child element</div>
</div>
You can access a specific element by getElementById('box'); and you can access its children by getElementById('box').children. So the first child would be getElementById('box').children[0] for example.
Did that help you ?
Id's are unique within the document so your ParentElement.someId.someId can simply be translated to document.getElementById(childId).
Regarding the sample CSS you posted, please note that you cannot have both situations in the same HTML at the same time, you can stylise differently based on the DOM hierarchy though. With this in mind, you can use the same document.getElementById(childId) call.
ID should be unique, so you really shouldn't have elements with the same ID over and over, instead you can use class.
To access the element though, first you get the parent:
var parent = document.getElementById("someId");
Then use querySelector on parent to get the desired element:
var element = parent.querySelector('.ELEMENT_CLASS');
And if it's id then:
var element = parent.querySelector('#ELEMENT_ID');

Get child-element from nested div

I have a div-structure like this:
<div id="company1">
<div class="space m-d p-r s-t">
<div class="zzr">
<div class="myTemplate">abc123</div>
</div>
</div>
</div>
I want to get the content form the class "myTemplate" over my "id"-div "company1"
Is it necessary to call all classes in my selector? Would be not good becaus of responsive design, the classes will change. So I woul prefer to call the "#company1" and then directly the "myTemplate". Tried this, but the content is empty and also the selector.
$('#company-'+currentTabIndex).children('.myTemplate').html()
//currentTabIndex has the current Tab-Index, in this case: 1
Firstly, the id property in your HTML has no - in it. Secondly, children looks at direct descendants, whereas you need to use find():
$('#company' + currentTabIndex).find('.myTemplate').html()
That said, you can use a single selector and remove the find() completely:
$('#company' + currentTabIndex + ' .myTemplate').html()
You want .find, not .children:
$('#company-'+currentTabIndex).find('.myTemplate').html()
.find looks for descendant elements. .children just looks for immediate children.
Or a single selector using the descendant combinator (the space before .myTemplate below — gotta love that name):
$('#company-' + currentTabIndex + ' .myTemplate').html()
See also Rory's note about the - in your selector, which isn't in your id. Either remove it from the selector, or add it to the id.
Children searches only for single level child elements, you have to use find().
$('#company-'+currentTabIndex).find('.myTemplate').html()
Given a jQuery object that represents a set of DOM elements, the
.children() method allows us to search through the children of these
elements in the DOM tree and construct a new jQuery object from the
matching elements. The .children() method differs from .find() in that
.children() only travels a single level down the DOM tree while
.find() can traverse down multiple levels to select descendant
elements (grandchildren, etc.) as well.
Reference: .find() - .children().
Instead of
$('#company-'+currentTabIndex).children('.myTemplate').html();
Try
$('#company'+currentTabIndex).find('.myTemplate').html(); //remove '-' from the selector
Use .find() instead of .children() as shown above.

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?

Categories