217

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.

8 Answers 8

361

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>

Sign up to request clarification or add additional context in comments.

4 Comments

Getting the parent by ID is not necessary in this case. document.getElementsByClassName would work fine.
@rvighne 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.
Might be good to edit this answer and change .innerHtml to .textContent for the security benefit of copy/paste coders.
And in 2022, how about some optional chaining on pretty much every '.'?
22

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!");

Comments

16

We can also make use of CSS selectors with querySelector

var targetDiv = document.querySelector('#foo .bar');
targetDiv.textContent = "Goodbye world!";

Comments

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!";
    }
}

10 Comments

getElementsByClassName doesn't work in IE8 either, but you can use querySelectorAll in its place (pretty much anyway).
@Ӫ_._Ӫ ... 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.
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.
@Ӫ_._Ӫ ... curious what do you see...because I am not seeing it.
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.
|
7

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}]`);
}

1 Comment

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')
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);
        }
    }
}

1 Comment

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; }
3

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>

2 Comments

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.
No, getElementById not working here. Only getElementsByClassName works
-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

2 Comments

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.
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.