0

I just can't fathom the logic, perhaps I'm over thinking it!

I need to make sure a script's id attribute is unique before I append it into the DOM.

Here are some examples to show you what I need:

If in the <head> element I had 3 child script elements, like:

<script id="script-0"></script>
<script id="script-1"></script>
<script id="script-2"></script>

I'd want my new script element to have an id of "script-3"

If I had 3 child script elements, like:

<script id="script-0"></script>
<script id="script-2"></script>
<script id="script-3"></script>

I'd want my new script element to have an id of "script-1" or "script-4"

And in this case:

<script id="script-1"></script>
<script id="script-2"></script>

I'd want my new script element to have an id of "script-0" or "script-3"

Just so long as the id attributes of each script element are unique!

In this scenario, each script element is actually doing a JSONP request, and therefore, as it's asynchronous, another script element may be added to the DOM in the interim and would need it's own unique id.

After the JSONP request has received a response it is removed from the DOM, hence the gaps in the id's, like script-0, script-1, script-3, script-4 and script-6 for example, as the JSONP requests script-2 and script-5 may have received a response and been removed from the DOM. In this case, I'd like a new script element to have either the id script-2, script-5 or, worst case: script-7.

I hope this is clear enough!

I just can't work out the logic, any help would be very much appreciated!

Oh, and only vanilla JS; no jQuery etc, thank you!

I promise to post an answer to a question on Stackoverflow for every answer posted in reply to this question! Promise!

Jonathon Oates
  • 2,912
  • 3
  • 37
  • 60

2 Answers2

1

You can do something like this:

var scripts = document.getElementsByTagName('script'); // we're getting all scripts from page
var ids = [];
for (i in scripts) {  // iterate by them
    var id = scripts[i].id;  // take 'id' attribute from current script 
    if (id && id.match(/script-\d+/)) {  // check if id matches 'script-...' pattern
        ids.push( parseInt(id.substring(id.indexOf('-')+1),10) );  // take only nomber and convert it to a decimal number, push this number to ids array
    }
}
ids = ids.sort(function(a,b){return a > b;});  // sort array ASC
var lastId = ids.pop();   // take the last value from array
Dmitrii Tarasov
  • 414
  • 2
  • 13
  • This is great, thank you! Could you just expand what each section is actually doing, so I know how it works and I'm not just copying code! That'd be a great help! – Jonathon Oates Oct 27 '11 at 22:14
1

Is it really necessary to fill the gaps?

I would imagine keeping a running counter and just incrementing it would be easier to work with, especially considering you can have up to 9,007,199,254,740,992 unique JSONP requests:

var requestJSONP = (function () {
    var guid = 0;

    return function (url) {
        var id = 'script-' + guid++;

        var script = document.createElement('script');
        script.id = id;
        script.src = url;
        script.type = 'text/javascript';

        script.onload = function () {
            this.parentNode.removeChild(this);
        };

        document.getElementsByTagName('head')[0].appendChild(script);

        return id;
    };
})();

The closure is optional, but it will prevent any other script from altering guid.

Example:

var scriptId = requestJSONP('/request/resource?callback=handler');
Community
  • 1
  • 1
Jonathan Lonowski
  • 121,453
  • 34
  • 200
  • 199
  • Would `guid` be persistent between calls? I would have thought that as it was a variable defined inside the `requestJSONP` function it would be reset to `0` each time the `requestJSONP` function was called? Also, if there was a script element, in the `head` element in the DOM, that for some reason (however remote the chance may be) that was called `script-0`, this code would be ignorant to that and create a script element with a duplicate `id`. That's if I've read and understood your code right? Thank you so much for your help so far! – Jonathon Oates Oct 27 '11 at 22:55
  • Sorry, to clarify: if there was a script element in the DOM, with the `id` `script-0` already, before `requestJSONP` was called, the code would be ignorant to this, and append a new script element to the DOM with a duplicate `id`. If I've understood your code right. Perhaps I was not clear enough, or just not quite quick enough to grasp your code's logic. Thank you for your help! – Jonathon Oates Oct 27 '11 at 23:03
  • @JonathonDavidOates Yeah, it'll persist. But, it's not defined within `requestJSONP`, but beside it within a closure. (it's actually defined by the `return function () { ... }`). But, yes, if another ` – Jonathan Lonowski Oct 27 '11 at 23:09
  • @JonathonDavidOates Also, if you're not too familiar with closures, you can learn about them [here](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) or on [MDN](https://developer.mozilla.org/en/JavaScript/Guide/Closures). – Jonathan Lonowski Oct 27 '11 at 23:19
  • To make sure, the first time `requestJSONP` was run, I could check to see if there are any script elements already in the head, and just start the count after that? I could also create a random number, on the first run, and use that to prefix all the JSONP scripts, e.g.: `5267364547-3` instead of `script-3`? – Jonathon Oates Oct 28 '11 at 07:44