Get element inside element by class and ID - JavaScript
Asked Answered
N

8

210

Alright, I've dabbled in JavaScript before, but the most useful thing I've written is a CSS style-switcher. So I'm somewhat new to this. Let's say I have HTML code like this:

<div id="foo">
    <div class="bar">
        Hello world!
    </div>
</div>

How would I change Hello world! to Goodbye world!?

I know how document.getElementsByClassName and document.getElementById work, but I would like to get more specific. Sorry if this has been asked before.

Northwest answered 19/10, 2011 at 0:45 Comment(0)
U
356

Well, first you need to select the elements with a function like getElementById.

var targetDiv = document.getElementById("foo").getElementsByClassName("bar")[0];

getElementById only returns one node, but getElementsByClassName returns a node list. Since there is only one element with that class name (as far as I can tell), you can just get the first one (that's what the [0] is for—it's just like an array).

Then, you can change the html with .textContent.

targetDiv.textContent = "Goodbye world!";

var targetDiv = document.getElementById("foo").getElementsByClassName("bar")[0];
targetDiv.textContent = "Goodbye world!";
<div id="foo">
    <div class="bar">
        Hello world!
    </div>
</div>
Ululate answered 19/10, 2011 at 0:47 Comment(4)
Getting the parent by ID is not necessary in this case. document.getElementsByClassName would work fine.Pindus
@Pindus the exact requirements of OP was that he "would like to get more specific". The person asking the question was asking how he could be more specific in his DOM tree traversal. The use of getElementByClassName was not a point of confusion, but I can see how someone might easily think I was indicating both as necessary. They are not. If you want to target only elements of a certain class that are under a particular node of a given ID as opposed to elements of that same class under a different node, this is what you would use.Ululate
Might be good to edit this answer and change .innerHtml to .textContent for the security benefit of copy/paste coders.Yeanling
And in 2022, how about some optional chaining on pretty much every '.'?Sievert
D
21

You can do it like this:

var list = document.getElementById("foo").getElementsByClassName("bar");
if (list && list.length > 0) {
    list[0].innerHTML = "Goodbye world!";
}

or, if you want to do it with with less error checking and more brevity, it can be done in one line like this:

document.getElementById("foo").getElementsByClassName("bar")[0].innerHTML = "Goodbye world!";

In explanation:

  1. You get the element with id="foo".
  2. You then find the objects that are contained within that object that have class="bar".
  3. That returns an array-like nodeList, so you reference the first item in that nodeList
  4. You can then set the innerHTML of that item to change its contents.

Caveats: some older browsers don't support getElementsByClassName (e.g. older versions of IE). That function can be shimmed into place if missing.


This is where I recommend using a library that has built-in CSS3 selector support rather than worrying about browser compatibility yourself (let someone else do all the work). If you want just a library to do that, then Sizzle will work great. In Sizzle, this would be be done like this:

Sizzle("#foo .bar")[0].innerHTML = "Goodbye world!";

jQuery has the Sizzle library built-in and in jQuery, this would be:

$("#foo .bar").html("Goodbye world!");
Demulsify answered 19/10, 2011 at 0:46 Comment(0)
J
11

We can also make use of CSS selectors with querySelector

var targetDiv = document.querySelector('#foo .bar');
targetDiv.textContent = "Goodbye world!";
Jerry answered 2/3, 2022 at 18:43 Comment(0)
K
7

If this needs to work in IE 7 or lower you need to remember that getElementsByClassName does not exist in all browsers. Because of this you can create your own getElementsByClassName or you can try this.

var fooDiv = document.getElementById("foo");

for (var i = 0, childNode; i <= fooDiv.childNodes.length; i ++) {
    childNode = fooDiv.childNodes[i];
    if (/bar/.test(childNode.className)) {
        childNode.innerHTML = "Goodbye world!";
    }
}
Karlik answered 19/10, 2011 at 0:53 Comment(10)
getElementsByClassName doesn't work in IE8 either, but you can use querySelectorAll in its place (pretty much anyway).Mirnamirror
@Ӫ_._Ӫ ... lol...your correct but you just prove my answer even more. You cannot rely on getElementsByClassName if your page needs to function across multiple browsers. jQuery would definately be an option but so whould the above code.Karlik
Yes, I meant that comment in support of your answer, but then also to point out that it's possible to use qSA in a shim so that you can still use native code in IE8. Although taking a closer look at your solution, you've got a few things that need fixing.Mirnamirror
@Ӫ_._Ӫ ... curious what do you see...because I am not seeing it.Karlik
var i = 0, var child = fooDiv.childNodes[i] is invalid. i <= fooDiv.childNodes doesn't really make sense. childNode.className.test("bar") There's no childNode variable, and a string doesn't have a test() method.Mirnamirror
@Ӫ_._Ӫ your correct about i<= fooDiv.childNodes as it should be i <= fooDiv.childNodes.length and my test() is screwed up but...var i = 0, var child = fooDiv.childnodes[i] is completely validKarlik
var i = 0, var child = fooDiv.childnodes[i] Nope, it's a syntax error. ;) You need to drop the second var because var is a statement, not an expression.Mirnamirror
@Ӫ_._Ӫ...wow my eyes are getting to me...this is what happens when you look at code too much with out testing.Karlik
That's much better, but your code is only ever testing the element at index 0, so the loop isn't necessary. If you meant to iterate over all child nodes, you'd need to do child = childNodes[i] inside the loop, otherwise you'll just test the first one over and over. In the example in the question, the first childNode will be a text node in many browsers, so there's that issue too. ;)Mirnamirror
...fixed it by changing child to childNode, and moving the assignment inside the loop. Having the assignment at the top would only work if you did for (var i = 0, childNode; childNode = fooDiv.childNodes[i]; i ++) { ... }Mirnamirror
H
6

The easiest way to do so is:

function findChild(idOfElement, idOfChild){
  let element = document.getElementById(idOfElement);
  return element.querySelector('[id=' + idOfChild + ']');
}

or better readable:

findChild = (idOfElement, idOfChild) => {
    let element = document.getElementById(idOfElement);
    return element.querySelector(`[id=${idOfChild}]`);
}
Hindbrain answered 27/10, 2017 at 22:47 Comment(1)
If the OP had asked about IDs, they could have just used getElementById on the idOfChild, since IDs must be unique to the document. But the OP asked about a class within an ID. And if you're using querySelector anyway, it would be "easier" to just use an appropriate selector: document.querySelector('#id .class')Coffey
W
4

you can use getElementById or getElementsByClassName on DOM Elements too. and not just the document

var targetDiv = document.getElementById("foo").getElementsByClassName("bar")[0];
targetDiv.textContent = "Goodbye world!";
<div id="foo">
    <div class="bar">
        Hello world!
    </div>
</div>
Wnw answered 15/11, 2021 at 21:33 Comment(1)
While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value.Hegarty
L
3

Recursive function :

function getElementInsideElement(baseElement, wantedElementID) {
    var elementToReturn;
    for (var i = 0; i < baseElement.childNodes.length; i++) {
        elementToReturn = baseElement.childNodes[i];
        if (elementToReturn.id == wantedElementID) {
            return elementToReturn;
        } else {
            return getElementInsideElement(elementToReturn, wantedElementID);
        }
    }
}
Lorrettalorri answered 18/10, 2015 at 13:17 Comment(1)
There is a minor bug in the sample above. Instead of instantly returning in the else path you have to check if something was found first. Otherwise the other child nodes will not be looped through. Something like this: if(elementToReturn) { return elementToReturn; }Oxazine
P
-8

You should not used document.getElementByID because its work only for client side controls which ids are fixed . You should use jquery instead like below example.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>                                                                                                             
<div id="foo">
   <div class="bar"> 
          Hello world!
     </div>
</div>

use this :

$("[id^='foo']").find("[class^='bar']")

// do not forget to add script tags as above

if you want any remove edit any operation then just add "." behind and do the operations

Pillsbury answered 1/8, 2015 at 18:22 Comment(2)
Using a thermonuclear weapon to kill a deer will work, but is slight overkill. Using a multi-kb jQuery library to select an element when Javascript offers that functionality in it's base code is slightly more overkill.Collyer
This answer only makes sense if you are using a framework like ASP.NET WebForms or some other server-side framework that creates IDs for you, ending with original, user-entered ID. No framework I'm aware of modifies CSS classes, so there is no reason to use an attribute selector on class.Coffey

© 2022 - 2024 — McMap. All rights reserved.