9

Is there a built in method or defacto default plugin that will let you automatically assign an unique ID to an element in jQuery, or do you need to implement something like this yourself? I'm looking for the jQuery equivalent to Prototype's identify method

Here's an example. I have some HTML structure on a page that looks like this

<span id="prefix_1">foo bar</span>
...
<div id="foo">
   <span></span>
   <span></span>
   <span></span>
</div>

I want to assign each of the spans an ID that will be unique to the page. So after calling something like this

$('#foo span').identify('prefix');   //fake code, no such method

The rendered DOM would look something like this

<span id="prefix_1">foo bar</span>
...
<div id="foo">
   <span id="prefix_2"></span>
   <span id="prefix_3"></span>
   <span id="prefix_4"></span>
</div>

Is there anything official-ish/robust for jQuery, or is this something most jQuery developers roll on their own?

Rob W
  • 341,306
  • 83
  • 791
  • 678
Alana Storm
  • 164,128
  • 91
  • 395
  • 599
  • 2
    I've never needed anything like this... What would you use it for? Keep in mind: jQuery works with sets of elements, while Prototype works with individual elements - you may be better off adjusting your logic to fit this model. – Shog9 Jan 22 '09 at 21:21
  • That's a really good point; I spent the last 6 months with prototype. I had originally written a jQuery widget/plugin that operated on a single page element, using the #id to hookup handlers. I figured the easiest way to expand my code to operate on a set would be an identify function. Clearly wrong – Alana Storm Jan 22 '09 at 21:38
  • Drop your comment in an answer if you still care about rep on the other side of 10k. – Alana Storm Jan 22 '09 at 21:39

5 Answers5

22
jQuery.fn.identify = function(prefix) {
    var i = 0;
    return this.each(function() {
        if(this.id) return;
        do { 
            i++;
            var id = prefix + '_' + i;
        } while($('#' + id).length > 0);            
        $(this).attr('id', id);            
    });
};

$('span').identify('test');

Tested this on:

<span id='test_2'></span>
<span>test1</span>
<span>test2</span>
<span>test3</span>

Turned it to:

<span id="test_2"></span>
<span id="test_1">test1</span>
<span id="test_3">test2</span>
<span id="test_4">test3</span>
Paolo Bergantino
  • 480,997
  • 81
  • 517
  • 436
  • 1
    The code works and is appreciated, but I'm still looking for something that's been around a while and proven itself in the wild (which is in no way a criticism on your provided code) – Alana Storm Jan 22 '09 at 21:27
  • I poked around the jQuery website before writing this and I couldn't find anything, but I get it where you're coming from. I think I covered everything, though. – Paolo Bergantino Jan 22 '09 at 21:32
3

Not that I know of, but you could do this yourself by adding the id attribute and supplying a GUID.

To add the attribute:

$(foo).attr( "id", createGuid() );

For the createGuid() implementation, see this question.

Note that you could easily turn this into a jQuery plug-in so that this function (you could even name it identify()) is available on any $-expression.

Community
  • 1
  • 1
Jason Cohen
  • 81,399
  • 26
  • 107
  • 114
  • Yeah, it's not *too* difficult a concept to implement. Another approach would be to store a reference count on the plugin function and increment it each time it was called. I was/am hoping for something more official that will catch any edge cases I haven't thought of. – Alana Storm Jan 22 '09 at 21:10
  • Understood and agreed about getting a more "native" method! I'm interested in a better answer too... – Jason Cohen Jan 22 '09 at 21:12
  • (The info/code is appreciated, and worth an up-vote, in case that wasn't obvious) – Alana Storm Jan 22 '09 at 21:21
2

Based on Paolo's solution:

jQuery.fn.identify = function(prefix) {
    var i = 0;
    return this.each(function() {
        if($(this).attr('id')) return;
        do { 
            i++;
            var id = prefix + '_' + i;
        } while($('#' + id).length > 0);            
        $(this).attr('id', id);            
    });
};

$('span').identify('test');

A small change that will avoid to re-count already used ids.

gizmo
  • 11,819
  • 6
  • 44
  • 61
  • This is how I had it originally, but if there is only element named 'test_2', it will jump straight to 'test_3' without ever doing 'test_1' - I am not sure if that is desired or not. – Paolo Bergantino Jan 22 '09 at 21:22
  • Yep, that's because of the "i" argument in the "each" call. I've remove it to avoid this issue. – gizmo Jan 22 '09 at 21:25
1

I'd modify the given function slightly and make it:

jQuery.fn.identify = function(prefix) {
    var i = 0;
    return this.each(function() {
        if($(this).attr('id')) return;
        do { 
            i++;
            var id = prefix + '_' + i;
        } while(document.getElementById(id) != null);            
        $(this).attr('id', id);            
    });
};

ID's could contain special characters that would require escaping in order to work properly with jQuery's CSS selector engine--like ".". So instead of finding them and escaping them, it's simpler and faster to replace it with the document method.

Andy Edinborough
  • 4,367
  • 1
  • 29
  • 28
-1

Maybe try

$("#foo span").each(function(){
   $(this).attr("id", "prefix_" + $(this).parent().index($(this)));
});
Birk
  • 2,173
  • 4
  • 21
  • 26