6

I have a legacy html document containing h1 elements which don't have ids. What I would like to achieve is to be able, using JavaScript, to get all h1(s) and then add to each a unique ID.

I have searched but could not find a solution that works.

Ian
  • 50,146
  • 13
  • 101
  • 111
ManUO
  • 347
  • 3
  • 4
  • 18
  • What format do you want the IDs in? And can you provide some example HTML? – MasNotsram May 16 '13 at 15:33
  • 2
    You can access any DOM element without an ID. Why do you need to do this? – Diodeus - James MacFarlane May 16 '13 at 15:33
  • 1
    Why? I can think of several reasons why you might want to, but the ones that might be useful would impose additional requirements beyond "unique". What problem are you trying to solve? If we know that, we can address the problem instead of what you think the solution is. – Quentin May 16 '13 at 15:34

2 Answers2

8

Try getting all of them with document.getElementsByTagName("h1"). Loop through them, check if they have an id, and work appropriately. Try:

var h1s = document.getElementsByTagName("h1");
for (var i = 0; i < h1s.length; i++) {
    var h1 = h1s[i];
    if (!h1.id) {
        h1.id = "h1" + i + (new Date().getTime());
    }
}

DEMO: http://jsfiddle.net/kTvA2/

After running the demo, if you inspect the DOM, you'll see 3 out of the 4 h1 elements have a new, unique id. The one with the id in the first place isn't changed.

Note that this code needs to run after all elements are ready/rendered, which can be achieved by putting the code inside of a window.onload handler. The demo provided is set up to implicitly run the code then.


UPDATE:

With jQuery, you could use:

$(document).ready(function () {
    $("h1:not([id])").attr("id", function (i, attr) {
        return "h1" + i + (new Date().getTime());
    });
});

DEMO: http://jsfiddle.net/kTvA2/7/

Ian
  • 50,146
  • 13
  • 101
  • 111
  • Fair solution, but why would one want to do this at all in the first place? – Pekka May 16 '13 at 15:34
  • @Pekka웃 Who the heck knows. Haha they said `I have a legacy html document`, so I'm not sure why they don't just change the HTML – Ian May 16 '13 at 15:35
  • Thanks for your quick replies and comments, all I really need to do is generate a table of content using the titles of all h1 tags. The script that I have for the TOC generation works only if my h1 tags have unique ids. – ManUO May 16 '13 at 15:36
  • 2
    @ManUO Is there any reason you can't find/replace the actual HTML? What do you need to do this for anyways? Setting the `id` for them is trivial - what will you use the `id` on these elements for later? – Ian May 16 '13 at 15:38
  • I could do with regex but then I don't know how to because once I find all h1 tags I am not able to add random numbers to the matched terms. – ManUO May 16 '13 at 15:41
  • @ManUO My point is - why do you think they **need** an `id` anyways? You really only give elements an `id` if you need to access them in JavaScript later. Do you plan on doing that? And if so, how? Because you want unique, generated `id` values, you won't be able to target them. – Ian May 16 '13 at 15:52
  • Yes, I need to access them to generate automatically table of content for the html content. – ManUO May 16 '13 at 15:55
  • @ManUO You probably need to put the code inside of `window.onload = function () { /* HERE */ };`. The jsFiddle I posted is setup to run like that (without explicitly having that code). – Ian May 16 '13 at 16:11
  • Thanks Ian, my function was using JQuery and was interfering with above code. – ManUO May 16 '13 at 17:01
  • @ManUO Ahh I see. I didn't know you were using jQuery - I updated my answer with a solution using jQuery, that I would prefer. – Ian May 16 '13 at 17:23
1

Use querySelectorAll() to get all of your header elements, then iterate over the result and generate yor unique id for each element.

var headerElements = document.querySelectorAll('h1');
for(h in headerElements) {
    if(headerElements[h] instanceof Element) {
        headerElements[h].id=uniqueIDgenerator();
    }
}
km6zla
  • 4,787
  • 2
  • 29
  • 51
  • I just tried the above without success in Firefox on Mac. I just used the above code first inside my html head section, then inside the body element without success. Am I doing something wrong? – ManUO May 16 '13 at 16:05
  • Why would you use a `for in` loop and have to check with `instanceof Element` when you can just use a normal `for` loop to loop over the indexes? – Ian May 16 '13 at 17:01
  • @Ian This is the way I know how to do it without jQuery. You are welcome to post an alternative response. I'd like to see an easier way. @ManUO I am not sure why it isn't working for you. I tested it in FF before I posted it. Note that you have to replace the placeholder function `uniqueIDgenerator()` with whatever you intend to use to generate your unique IDs. – km6zla May 16 '13 at 17:10
  • @ogc-nick My point was that instead of your `for in` loop, you can use `for (var i = 0; i < headerElements; i++) { headerElements[i].id = uniqueIDgenerator(); }`. You shouldn't use `for in` to loop over elements in an array - it's for looping over the keys in an object – Ian May 16 '13 at 17:17
  • @ogc-nick No problem :) Here's a reference you can read if you want - http://stackoverflow.com/questions/500504/why-is-using-for-in-with-array-iteration-such-a-bad-idea . – Ian May 16 '13 at 17:34