XHTML-Compliant Technique for Passing Parameters to Javascript Script Files
Joe Brinkman posted a technique to pass parameters to Javascript script files. The approach is simple — append a standard querystring to the script URL and obtain the parameters by locating the script element using the ID attribute, and parsing the key-value pairs from the “src” attribute. A sample usage is like this:
<script id="MyScript" src="http://www.foo.com/myscript.js?obj1=ABC&amp;obj2=XYZ" type="text/javascript"></script>
This is a great approach and works well for most scenarios, except in those situations where HTML 4.01 Strict markup is desired. In this case there are two problems that would cause validation to fail:
1) The HTML “script” element does not support an ID attribute. Yes, this is true. Verify it for yourself here.
2) The ampersand (“&”) character is a predefined entity and must be expressed as an entity reference “&”
So, is there a simple way to work around this issue. Of course, otherwise the title of this post would be totally false advertising.
Here is the revised code snippet I propose in lieu of the one above:
<script src="http://www.foo.com/myscript.js#obj1/ABC/obj2/XYZ" type="text/javascript">
Let’s break it down.
1) The ID attribute has been removed. Even without the ID attribute there is still a simple way to reference the script element. The trick is to take advantage of the fact that as the browser is rendering the page, it executes JS code immediately when encountered. As a result, if the code in your JS file queries the DOM, the last script element in the DOM is a self-reference (i.e. a reference to the script element that loaded the code being executed). Thus, using document.getElementsByTagName(“script”) and referencing the last element in the array, provides an easy way to get the current script reference.
2) The standard querystring separator “?” has been replaced by “#”. This is not necessary, but something I did for semantic reasons. To overcome the “&” entity issue, I used a slash (“/”) character for separating not only key-value pairs, but keys and values too. The reason for this will become evident in a bit, but since I modified the querystring to something non-standard, I felt it was important to also remove the “?” separator which is a prefix for querystring. Instead, I used a hash (“#”) character which is a pointer to a document fragment and does not have any semantic value in the context of a JS script URL. (In fact the JS URL hash technique is a common way to pass data in cross-domain XMLHttp requests for this reason and also because it does not cause a page re-load.)
3) Key-Value pairs. The last change I made is to use a path-based approach to key-value pairs instead of Key=Value format. I did this because it is a common technique in RESTful URL’s, is easier to read and much simpler to parse. In fact, using a single “for…” loop, it becomes a trivial task to create an associative array of all the parameters for ready reference.
Here’s the code wrapped into a function with a sample call:
var myParams = getScriptUrlParams(); alert(myParams["obj1"]); alert(myParams["obj2"]); function getScriptUrlParams() { var scriptTags = document.getElementsByTagName("script"); // This code is assumed to be in a file so the "src" attribute // is guaranteed to be present...no error-checking is needed var urlFrags = scriptTags[scriptTags.length-1].src.split("#"); var urlParams=[]; var urlParamRaw = []; if (urlFrags.length > 1) { urlParamRaw = urlFrags[1].split("/"); if (urlParamRaw.length >= 2) { for(var param=0;param<urlParamRaw.length;param+=2) urlParams[urlParamRaw[param]] = (urlParamRaw.length >= param + 1 ? unescape(urlParamRaw[param+1]) : null); } } return(urlParams); }
What do you think? Is this a simpler approach or is it more complicated? Are there other techniques for working around the XHTML validation issue.
Ali Khan
one correction the line in the for loop should be:
urlParams[urlParamRaw[param]] = (urlParamRaw.length >= param + 1 ? unescape(urlParamRaw[param+1]) : null);
Other wise great thanks
techbubble
Good catch...thank you. I have updated the code in the post.