18

When coding with JS and the DOM I find myself constantly needing to generate ids (or names) that have no purpose other than to group DOM elements together (or relate them to each other)1.

These ids (or names) will not be mentioned explicitly anywhere else in the code, and therefore they could be any random strings, and, for the case of ids, they must be unique.

Is there a standard way in JavaScript to automatically generate unique ids?


1A situation that illustrates such use of identifiers arises at the time of grouping (say) radio buttons and linking them to their associated labels...

My (naive noob's) alternative to the brain-numbing task of writing HTML like this

<input type="radio" name="sys" id="sys-0" value="lnx"> <label for="sys-0"> Linux   </label> <br>
<input type="radio" name="sys" id="sys-1" value="osx"> <label for="sys-1"> OS X    </label> <br>
<input type="radio" name="sys" id="sys-2" value="win"> <label for="sys-2"> Windows </label>

(which requires repeating each sys-based identifier three times per button-label pair) is to just write

<div class="button-group" name="sys">
  <input type="radio" value="lnx"> <label> Linux   </label> <br>
  <input type="radio" value="osx"> <label> OS X    </label> <br>
  <input type="radio" value="win"> <label> Windows </label>
</div>

and then use some JS to group the buttons under one name attribute, and link the labels to their respective buttons:

$('.button-group').each(function (i, e) {
  var name = $(e).attr('name');
  $(e).find(':radio').each(function (j, f) {
    var id = name + '-' + j;
    $(f).attr('name', name)
        .attr('id', id)
      .next()
        .attr('for', id);
  })
});

This works fine, but it still requires me to come up with names for these button groups and unique ids for the buttons, names and ids that are otherwise useless to me. I'd just as soon avoid all this gratuitous naming business with something like

<div class="button-group">
  <input type="radio" value="lnx"> <label> Linux   </label> <br>
  <input type="radio" value="osx"> <label> OS X    </label> <br>
  <input type="radio" value="win"> <label> Windows </label>
</div>

$('.button-group').each(function (i, e) {
  var name = unique_id();
  $(e).find(':radio').each(function (j, f) {
    var id = unique_id();
    $(f).attr('name', name)
        .attr('id', id)
      .next()
        .attr('for', id);
  })
});

Of course I could roll my own implementation of unique_id, but I thought I'd ask before I reinvent this very obvious-looking wheel.

8
  • Have a look at this: chancejs.com Commented Nov 19, 2013 at 0:41
  • You are relying on needing ID selectors too much...there are lots of ways to use jQuery without needing ID...and it is generally easier than your approach Commented Nov 19, 2013 at 0:43
  • 1
    @charlietfl the question includes a good example: generating a name for radio buttons. Commented Nov 19, 2013 at 0:50
  • 2
    if jQurey ui > 1.9 is used then you have uniqueId Commented Nov 19, 2013 at 0:50
  • 1
    An alternate solution would be to nest the inputs inside the label elements. According to Mozilla (developer.mozilla.org/en-US/docs/Web/HTML/Element/label): "The HTML <label> Element represents a caption for an item in a user interface. It can be associated with a control either by using the for attribute, or by placing the control element inside the label element." Commented Nov 19, 2013 at 1:02

4 Answers 4

16

One approach which I've used is

(function(){
    var counter = 0;
    window.uniqueId = function(){
        return 'myid-' + counter++
    }
});

then

$('.button-group').each(function (i, e) {
  var name = uniqueId();
  $(e).find(':radio').each(function (j, f) {
    var id = uniqueId();
    $(f).attr('name', name)
        .attr('id', id)
      .next()
        .attr('for', id);
  })
});
Sign up to request clarification or add additional context in comments.

1 Comment

Creating uniqueId in the global scope doesn't sound like a good idea. Picture multiple applications on the page relying on such a module...
7

I agree with some of the commenters that there are probably better ways to do this, but a simple implementation of unique_id() you could use would be:

return Math.random().toString(36);

4 Comments

Why use a random number, when a simple incrementing counter (as in Arun's answer) works fine and guarantees no repetition and is perhaps easier to work with when debugging (easier to recognize small numbers).
The global counter might be a little bit better, but I think the advantages are very minimal. This also works fine, you can also reasonably assume no collisions and although harder for inspecting the dom by hand, it's a bit easier to write/read the code.
Assuming non-collision is bad. Random number generation aims at creating true randomness which by design involves producing equal values. For a single-threaded application, such as every JavaScript application, the auto-increment counter is the simplest and indeed the fastest solution. You don't even need to mess with the global scope, you could keep the counter as part of the function object itself: function uid() { return uid.__current++; }; uid.__current = 0;
The probability of collisions with counter schemes is higher in practice than with Random: there will likely be multiple libraries involved, and each could have its own independent counters, thus coming up with collision if the prefix/suffix is the same...
5

A common approach - for example in ajax calls - is to use new Date().getTime().

If you are worried that you might output the same id twice, you can always add a validation step:

do {uniqueID=new Date().getTime();} while (document.getElementById(uniqueID));

4 Comments

If you're trying to generate a series of unique IDs, this can be very wasteful. In my browser I can generate around 2700 ID's per millisecond, but with this code it'd always be at most 1, and it'd be busy the whole time. Of course if you need only 2 or 3 IDs then it's okay.
@Mark that's true. The advantage of this method, compared to a counter, is that it'll still work if multiple independent scripts ("apps") need to generate ids on the same page.
although that could be made to work with the global method, you're right that there are cases where the date-method is just fine and easier.
You can combine both: global plus serial. Double win!
-1

Example of working with radio labels without ID:

<div class="button-group" name="sys">
  <input type="radio" value="lnx" name="radio1"> <label> Linux   </label> <br>
  <input type="radio" value="osx"  name="radio1"> <label> OS X    </label> <br>
  <input type="radio" value="win"  name="radio1"> <label> Windows </label>
</div>


   <div class="content">
       <div>Show me when 1st radio checked</div> 
       <div>Show me when 2nd radio checked</div> 
       <div>Show me when 3rdd radio checked</div>
   </div>

JS

$('.button-group[name=sys] :radio').change(function(){
    $(this).parent().find('label').removeClass('active');
     $(this).next().addClass('active');

      /* index radios vs content*/

      var radioIndex=$('.button-group[name=sys] :radio').index(this);
       /* hide all the content div, show one that matches radio index*/
       $('.content div').hide().eq(radioIndex).show();
})

6 Comments

They still need a name attribute to group them properly.
@Sam yup, sure do...grabbed html from above and was focused on traversing vs valid names..thx
Thanks, but you're assuming that I want the IDs so that I can access the radio labels, and this assumption is incorrect. In fact, in my post I explicitly stated that the IDs in question are not used at all by my code. More to the point, there are many more other situations where the need for such gratuitous naming arises, and that cannot be handled the way you propose. For example, when working with d3.js I constantly need to assign classes to objects, classes whose only purpose is allow selecting those objects as a group. In such situations too...
...I find myself having to generate identifiers that are otherwise useless.
so marry them on render from objject... and this was explicitely stated in your question A situation that illustrates such use of identifiers arises at the time of grouping (say) radio buttons and linking them to their associated labels... Based on that was trying to be helpful
|

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.