load javascript with paramater in its url [duplicate] - javascript

In my HTML file I have linked to the JS with:
src="myscript.js?config=true"
Can my JS directly read the value of this var like this?
alert (config);
This does not work, and the FireFox Error Console says "config is not defined". How do I read the vars passed via the src attribute in the JS file? Is it this simple?

<script>
var config=true;
</script>
<script src="myscript.js"></script>
You can't pass variables to JS the way you tried. SCRIPT tag does not create a Window object (which has a query string), and it is not server side code.

Yes, you can, but you need to know the exact script file name in the script :
var libFileName = 'myscript.js',
scripts = document.head.getElementsByTagName("script"),
i, j, src, parts, basePath, options = {};
for (i = 0; i < scripts.length; i++) {
src = scripts[i].src;
if (src.indexOf(libFileName) != -1) {
parts = src.split('?');
basePath = parts[0].replace(libFileName, '');
if (parts[1]) {
var opt = parts[1].split('&');
for (j = opt.length-1; j >= 0; --j) {
var pair = opt[j].split('=');
options[pair[0]] = pair[1];
}
}
break;
}
}
You have now an 'options' variable which has the arguments passed. I didn't test it, I changed it a little from http://code.google.com/p/canvas-text/source/browse/trunk/canvas.text.js where it works.

You might have seen this done, but really the JS file is being preprocessed server side using PHP or some other language first. The server side code will print/echo the javascript with the variables set. I've seen a scripted ad service do this before, and it made me look into seeing if it can be done with plain ol' js, but it can't.

You need to use Javascript to find the src attribute of the script and parse the variables after the '?'. Using the Prototype.js framework, it looks something like this:
var js = /myscript\.js(\?.*)?$/; // regex to match .js
var jsfile = $$('head script[src]').findAll(function(s) {
return s.src.match(js);
}).each(function(s) {
var path = s.src.replace(js, ''),
includes = s.src.match(/\?.*([a-z,]*)/);
config = (includes ? includes[1].split('=');
alert(config[1]); // should alert "true" ??
});
My Javascript/RegEx skills are rusty, but that's the general idea. Ripped straight from the scriptaculous.js file!

Your script can however locate its own script node and examine the src attribute and extract whatever information you like.
var scripts = document.getElementsByTagName ('script');
for (var s, i = scripts.length; i && (s = scripts[--i]);) {
if ((s = s.getAttribute ('src')) && (s = s.match (/^(.*)myscript.js(\?\s*(.+))?\s*/))) {
alert ("Parameter string : '" + s[3] + "'");
break;
}
}

Whether or not this SHOULD be done, is a fair question, but if you want to do it, http://feather.elektrum.org/book/src.html really shows how. Assuming your browser blocks when rendering script tags (currently true, but may not be future proof), the script in question is always the last script on the page up to that point.
Then using some framework and plugin like jQuery and http://plugins.jquery.com/project/parseQuery this becomes pretty trivial. Surprised there's not a plugin for it yet.
Somewhat related is John Resig's degrading script tags, but that runs code AFTER the external script, not as part of the initialization: http://ejohn.org/blog/degrading-script-tags/
Credits: Passing parameters to JavaScript files , Passing parameters to JavaScript files

Using global variables is not a so clean or safe solution, instead you can use the data-X attributes, it is cleaner and safer:
<script type="text/javascript" data-parameter_1="value_1" ... src="/js/myfile.js"></script>
From myfile.js you can access the data parameters, for instance with jQuery:
var parameter1 = $('script[src*="myfile.js"]').data('parameter_1');
Obviously "myfile.is" and "parameter_1" have to match in the 2 sources ;)

You can do that with a single line code:
new URL($('script').filter((a, b, c) => b.src.includes('myScript.js'))[0].src).searchParams.get("config")

It's simpler if you pass arguments without names, just like function calls.
In HTML:
<script src="abc.js" data-args="a,b"></script>
Then, in JavaScript:
const args=document.currentScript.dataset.args.split(',');
Now args contains the array ['a','b'].

Related

How to pass arguments to external Javascript files? [duplicate]

I read the tutorial DIY widgets - How to embed your site on another site for XSS Widgets by Dr. Nic.
I'm looking for a way to pass parameters to the script tag. For example, to make the following work:
<script src="http://path/to/widget.js?param_a=1&param_b=3"></script>
Is there a way to do this?
Two interesting links:
How to embed Javascript widget that depends on jQuery into an unknown environment (Stackoverflow discussion)
An article on passing parameters to a script tag
I apologise for replying to a super old question but after spending an hour wrestling with the above solutions I opted for simpler stuff.
<script src=".." one="1" two="2"></script>
Inside above script:
document.currentScript.getAttribute('one'); // 1
document.currentScript.getAttribute('two'); // 2
Much easier than jQuery or URL parsing.
You might need the polyfill for document.currentScript from #Yared Rodriguez's answer for IE:
document.currentScript = document.currentScript || (function() {
var scripts = document.getElementsByTagName('script');
return scripts[scripts.length - 1];
})();
It's better to Use feature in html5 5 data Attributes
<script src="http://path.to/widget.js" data-width="200" data-height="200">
</script>
Inside the script file http://path.to/widget.js you can get the paremeters in that way:
<script>
function getSyncScriptParams() {
var scripts = document.getElementsByTagName('script');
var lastScript = scripts[scripts.length-1];
var scriptName = lastScript;
return {
width : scriptName.getAttribute('data-width'),
height : scriptName.getAttribute('data-height')
};
}
</script>
Got it. Kind of a hack, but it works pretty nice:
var params = document.body.getElementsByTagName('script');
query = params[0].classList;
var param_a = query[0];
var param_b = query[1];
var param_c = query[2];
I pass the params in the script tag as classes:
<script src="http://path.to/widget.js" class="2 5 4"></script>
This article helped a lot.
Another way is to use meta tags. Whatever data is supposed to be passed to your JavaScript can be assigned like this:
<meta name="yourdata" content="whatever" />
<meta name="moredata" content="more of this" />
The data can then be pulled from the meta tags like this (best done in a DOMContentLoaded event handler):
var data1 = document.getElementsByName('yourdata')[0].content;
var data2 = document.getElementsByName('moredata')[0].content;
Absolutely no hassle with jQuery or the likes, no hacks and workarounds necessary, and works with any HTML version that supports meta tags...
JQuery has a way to pass parameters from HTML to javascript:
Put this in the myhtml.html file:
<!-- Import javascript -->
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<!-- Invoke a different javascript file called subscript.js -->
<script id="myscript" src="subscript.js" video_filename="foobar.mp4">/script>
In the same directory make a subscript.js file and put this in there:
//Use jquery to look up the tag with the id of 'myscript' above. Get
//the attribute called video_filename, stuff it into variable filename.
var filename = $('#myscript').attr("video_filename");
//print filename out to screen.
document.write(filename);
Analyze Result:
Loading the myhtml.html page has 'foobar.mp4' print to screen. The variable called video_filename was passed from html to javascript. Javascript printed it to screen, and it appeared as embedded into the html in the parent.
jsfiddle proof that the above works:
http://jsfiddle.net/xqr77dLt/
Create an attribute that contains a list of the parameters, like so:
<script src="http://path/to/widget.js" data-params="1, 3"></script>
Then, in your JavaScript, get the parameters as an array:
var script = document.currentScript ||
/*Polyfill*/ Array.prototype.slice.call(document.getElementsByTagName('script')).pop();
var params = (script.getAttribute('data-params') || '').split(/, */);
params[0]; // -> 1
params[1]; // -> 3
If you are using jquery you might want to consider their data method.
I have used something similar to what you are trying in your response but like this:
<script src="http://path.to/widget.js" param_a = "2" param_b = "5" param_c = "4">
</script>
You could also create a function that lets you grab the GET params directly (this is what I frequently use):
function $_GET(q,s) {
s = s || window.location.search;
var re = new RegExp('&'+q+'=([^&]*)','i');
return (s=s.replace(/^\?/,'&').match(re)) ? s=s[1] : s='';
}
// Grab the GET param
var param_a = $_GET('param_a');
Thanks to the jQuery, a simple HTML5 compliant solution is to create an extra HTML tag, like div, to store the data.
HTML:
<div id='dataDiv' data-arg1='content1' data-arg2='content2'>
<button id='clickButton'>Click me</button>
</div>
JavaScript:
$(document).ready(function() {
var fetchData = $("#dataDiv").data('arg1') +
$("#dataDiv").data('arg2') ;
$('#clickButton').click(function() {
console.log(fetchData);
})
});
Live demo with the code above: http://codepen.io/anon/pen/KzzNmQ?editors=1011#0
On the live demo, one can see the data from HTML5 data-* attributes to be concatenated and printed to the log.
Source: https://api.jquery.com/data/
it is a very old thread, I know but this might help too if somebody gets here once they search for a solution.
Basically I used the document.currentScript to get the element from where my code is running and I filter using the name of the variable I am looking for. I did it extending currentScript with a method called "get", so we will be able to fetch the value inside that script by using:
document.currentScript.get('get_variable_name');
In this way we can use standard URI to retrieve the variables without adding special attributes.
This is the final code
document.currentScript.get = function(variable) {
if(variable=(new RegExp('[?&]'+encodeURIComponent(variable)+'=([^&]*)')).exec(this.src))
return decodeURIComponent(variable[1]);
};
I was forgetting about IE :) It could not be that easier... Well I did not mention that document.currentScript is a HTML5 property. It has not been included for different versions of IE (I tested until IE11, and it was not there yet). For IE compatibility, I added this portion to the code:
document.currentScript = document.currentScript || (function() {
var scripts = document.getElementsByTagName('script');
return scripts[scripts.length - 1];
})();
What we are doing here is to define some alternative code for IE, which returns the current script object, which is required in the solution to extract parameters from the src property. This is not the perfect solution for IE since there are some limitations; If the script is loaded asynchronously. Newer browsers should include ".currentScript" property.
I hope it helps.
This is the Solution for jQuery 3.4
<script src="./js/util.js" data-m="myParam"></script>
$(document).ready(function () {
var m = $('script[data-m][data-m!=null]').attr('data-m');
})
Put the values you need someplace where the other script can retrieve them, like a hidden input, and then pull those values from their container when you initialize your new script. You could even put all your params as a JSON string into one hidden field.
It's simpler if you pass arguments without names, just like function calls.
In HTML:
<script src="abc.js" data-args="a,b"></script>
Then, in JavaScript:
const args=document.currentScript.dataset.args.split(',');
Now args contains the array ['a','b']. This assumes synchronous script calling.
I wanted solutions with as much support of old browsers as possible. Otherwise I'd say either the currentScript or the data attributes method would be most stylish.
This is the only of these methods not brought up here yet. Particularly, if for some reason you have great amounts of data, then the best option might be:
localStorage
/* On the original page, you add an inline JS Script.
* If you only have one datum you don't need JSON:
* localStorage.setItem('datum', 'Information here.');
* But for many parameters, JSON makes things easier: */
var data = {'data1': 'I got a lot of data.',
'data2': 'More of my data.',
'data3': 'Even more data.'};
localStorage.setItem('data', JSON.stringify(data));
/* External target JS Script, where your data is needed: */
var data = JSON.parse(localStorage.getItem('data'));
console.log(data['data1']);
localStorage has full modern browser support, and surprisingly good support of older browsers too, back to IE 8, Firefox 3,5 and Safari 4 [eleven years back] among others.
If you don't have a lot of data, but still want extensive browser support, maybe the best option is:
Meta tags [by Robidu]
/* HTML: */
<meta name="yourData" content="Your data is here" />
/* JS: */
var data1 = document.getElementsByName('yourData')[0].content;
The flaw of this, is that the correct place to put meta tags [up until HTML 4] is in the head tag, and you might not want this data up there. To avoid that, or putting meta tags in body, you could use a:
Hidden paragraph
/* HTML: */
<p hidden id="yourData">Your data is here</p>
/* JS: */
var yourData = document.getElementById('yourData').innerHTML;
For even more browser support, you could use a CSS class instead of the hidden attribute:
/* CSS: */
.hidden {
display: none;
}
/* HTML: */
<p class="hidden" id="yourData">Your data is here</p>

how to pass javascript variable from one js to another js without jquery?

I am beginner in web development. I am trying to send variable from one js file to another js file .
I researched alot before posting this question. I couldn't find any particular method by which i can do this.
My script which defines variable is
function getEventData(){
var eventList = document.getElementsByName("events");
var k=0;
var url = "https://www.eventbriteapi.com/v3/events/search/?categories=";
for(var i=0;i<eventList.length;i++){
if(k>=3)
break;
if(eventList[i].checked){
if(k==2)
url+=eventList[i].value+"";
else
url+=eventList[i].value+",";
k++;
}
}
url+="&token=************";
}
The url variable is perfect. I want to use it in another script which is
var jsonData=getJSON('url').then(function(data)
{
var sjd="";
for(var i=0; i<data.events.length; i++)
{
var url = data.events[i].name.url;
sjd +='<h4>'+ "<br/>"+ data.events[i].name.text + '<br>'+'</h4>';
}
document.getElementById("events").innerHTML = sjd ;
}
);
As seen i want to use the url variable from first js to second which is used in getJSON function.
I found local storage and cookies as a possible way. But storage doesnt work even if i use the link stated in comment. I cant find any good resource where i can learn cookies. Also is there any other way possible?
As suggested, use localStorage to store do the job.
localStorage.setItem("myvar", "jour json serialised string of variable");
and on the other page use it
var myvar = localStorage.getItem("myvar");
Again, deserialise on the other page. JSON.stringify is something you should know already. Also jquery has jStore plugin for this.

javascript replace string in js file

Ok so another issue i got
I have a js file that i need to include on my page (i dont have access to edit this js file)
Inside that javascript there is a function wich has a line that i need to edit a variable in there.
lets assume:
Code:
var links = [{"offer_id":"1","title":"Text!","url":"http:\/\/www.site.com\/tracker\/1\/?http:\/\/site.com\/click.php?aff=9917&camp=5626&crt=13346&sid=e6a00014f247fe39de1b_1","footer_text":"text","blank_referrer":"1","active":"1","value":"0.40","creation_time":"1327785202"}];
notice : '&sid=e6a00014f247fe39de1b_1'
i need to add something right after sid=
so that i becomes for example:
Code:
&sid=AlssfIT_e6a00014f247fe39de1b_1
i added: AlssfIT_
any ideas how to achieve this ?
i tried something like
Code:
str.replace("&sid=","&sid="+kwd);
right after i "include" the js file but aparently is not working
I think you're going about it the wrong way. If notice is a variable in the global space you can just replace it normally.
window.someObject.notice = window.someObject.notice.replace("&sid=","&sid="+kwd);
This will of course only work if notice is a variable that is navigable to in the global namespace and is not inside a closure. It is inside a closure if it has a var declaration inside a function() {...}
But, assuming that there is global access to that variable, that will be your easiest way to achieve this.
If not, you can try grabbing the contents of the script and executing it hopefully overwriting the original code. This will only work if your script and the script you are fetching are from the same origin (domain, subdomain, port, protocol, a few other things) - it is impossible otherwise due to the _Same Origin Policy_
Assuming you are at the same origin, you could do something like this (using jquery for simplicity)
( function() {
// First we need the url of the script, we can grab it out of the element directly or it can be hard coded
var scriptLocation = $('script#the-id-of-the-script-element').prop('src');
// Now that we have the location fetch the script again so we can get it as plaintext
// this will usually not do another HTTP request since your browser has it cached
$.get(scriptLocation).done(function(text) { // I prefer the deferred syntax as being more explicit, this is equivalent to $.get(scriptLocation, function(text) {
var newText = text.replace("&sid=","&sid="+kwd);
eval(newText);
});
} )()
Something like this could work.
try regex: (not tested)
myregexp = new RegExp("/&sid=/", "gims");
str.replace(myregexp, "&sid=" + kwd);

Passing parameters to JavaScript files

Often I will have a JavaScript file that I want to use which requires certain variables be defined in my web page.
So the code is something like this:
<script type="text/javascript" src="file.js"></script>
<script type="text/javascript">
var obj1 = "somevalue";
</script>
But what I want to do is:
<script type="text/javascript"
src="file.js?obj1=somevalue&obj2=someothervalue"></script>
I tried different methods and the best one yet is to parse the query string like this:
var scriptSrc = document.getElementById("myscript").src.toLowerCase();
And then search for my values.
I wonder if there is another way to do this without building a function to parse my string.
Do you all know other methods?
I'd recommend not using global variables if possible. Use a namespace and OOP to pass your arguments through to an object.
This code belongs in file.js:
var MYLIBRARY = MYLIBRARY || (function(){
var _args = {}; // private
return {
init : function(Args) {
_args = Args;
// some other initialising
},
helloWorld : function() {
alert('Hello World! -' + _args[0]);
}
};
}());
And in your html file:
<script type="text/javascript" src="file.js"></script>
<script type="text/javascript">
MYLIBRARY.init(["somevalue", 1, "controlId"]);
MYLIBRARY.helloWorld();
</script>
You can pass parameters with arbitrary attributes. This works in all recent browsers.
<script type="text/javascript" data-my_var_1="some_val_1" data-my_var_2="some_val_2" src="/js/somefile.js"></script>
Inside somefile.js you can get passed variables values this way:
........
var this_js_script = $('script[src*=somefile]'); // or better regexp to get the file name..
var my_var_1 = this_js_script.attr('data-my_var_1');
if (typeof my_var_1 === "undefined" ) {
var my_var_1 = 'some_default_value';
}
alert(my_var_1); // to view the variable value
var my_var_2 = this_js_script.attr('data-my_var_2');
if (typeof my_var_2 === "undefined" ) {
var my_var_2 = 'some_default_value';
}
alert(my_var_2); // to view the variable value
...etc...
Another idea I came across was assigning an id to the <script> element and passing the arguments as data-* attributes. The resulting <script> tag would look something like this:
<script id="helper" data-name="helper" src="helper.js"></script>
The script could then use the id to programmatically locate itself and parse the arguments. Given the previous <script> tag, the name could be retrieved like this:
var name = document.getElementById("helper").getAttribute("data-name");
We get name = helper
Check out this URL. It is working perfectly for the requirement.
http://feather.elektrum.org/book/src.html
Thanks a lot to the author. For quick reference I pasted the main logic below:
var scripts = document.getElementsByTagName('script');
var myScript = scripts[ scripts.length - 1 ];
var queryString = myScript.src.replace(/^[^\?]+\??/,'');
var params = parseQuery( queryString );
function parseQuery ( query ) {
var Params = new Object ();
if ( ! query ) return Params; // return empty object
var Pairs = query.split(/[;&]/);
for ( var i = 0; i < Pairs.length; i++ ) {
var KeyVal = Pairs[i].split('=');
if ( ! KeyVal || KeyVal.length != 2 ) continue;
var key = unescape( KeyVal[0] );
var val = unescape( KeyVal[1] );
val = val.replace(/\+/g, ' ');
Params[key] = val;
}
return Params;
}
You use Global variables :-D.
Like this:
<script type="text/javascript">
var obj1 = "somevalue";
var obj2 = "someothervalue";
</script>
<script type="text/javascript" src="file.js"></script">
The JavaScript code in 'file.js' can access to obj1 and obj2 without problem.
EDIT Just want to add that if 'file.js' wants to check if obj1 and obj2 have even been declared you can use the following function.
function IsDefined($Name) {
return (window[$Name] != undefined);
}
Hope this helps.
Here is a very rushed proof of concept.
I'm sure there are at least 2 places where there can be improvements, and I'm also sure that this would not survive long in the wild. Any feedback to make it more presentable or usable is welcome.
The key is setting an id for your script element. The only catch is that this means you can only call the script once since it looks for that ID to pull the query string. This could be fixed if, instead, the script loops through all query elements to see if any of them point to it, and if so, uses the last instance of such an script element. Anyway, on with the code:
Script being called:
window.onload = function() {
//Notice that both possible parameters are pre-defined.
//Which is probably not required if using proper object notation
//in query string, or if variable-variables are possible in js.
var header;
var text;
//script gets the src attribute based on ID of page's script element:
var requestURL = document.getElementById("myScript").getAttribute("src");
//next use substring() to get querystring part of src
var queryString = requestURL.substring(requestURL.indexOf("?") + 1, requestURL.length);
//Next split the querystring into array
var params = queryString.split("&");
//Next loop through params
for(var i = 0; i < params.length; i++){
var name = params[i].substring(0,params[i].indexOf("="));
var value = params[i].substring(params[i].indexOf("=") + 1, params[i].length);
//Test if value is a number. If not, wrap value with quotes:
if(isNaN(parseInt(value))) {
params[i] = params[i].replace(value, "'" + value + "'");
}
// Finally, use eval to set values of pre-defined variables:
eval(params[i]);
}
//Output to test that it worked:
document.getElementById("docTitle").innerHTML = header;
document.getElementById("docText").innerHTML = text;
};
Script called via following page:
<script id="myScript" type="text/javascript"
src="test.js?header=Test Page&text=This Works"></script>
<h1 id="docTitle"></h1>
<p id="docText"></p>
might be very simple
for example
<script src="js/myscript.js?id=123"></script>
<script>
var queryString = $("script[src*='js/myscript.js']").attr('src').split('?')[1];
</script>
You can then convert query string into json like below
var json = $.parseJSON('{"'
+ queryString.replace(/&/g, '","').replace(/=/g, '":"')
+ '"}');
and then can use like
console.log(json.id);
This can be easily done if you are using some Javascript framework like jQuery.
Like so,
var x = $('script:first').attr('src'); //Fetch the source in the first script tag
var params = x.split('?')[1]; //Get the params
Now you can use these params by splitting as your variable parameters.
The same process can be done without any framework but will take some more lines of code.
Well, you could have the javascript file being built by any of the scripting languages, injecting your variables into the file on every request. You would have to tell your webserver to not dish out js-files statically (using mod_rewrite would suffice).
Be aware though that you lose any caching of these js-files as they are altered constantly.
Bye.
HTML:
<script src='greet.js' data-param1='hello' data-param2='world'></script>
// greet.js:
const prm1=document.currentScript.dataset.param1;
const prm2=document.currentScript.dataset.param2;
Nice question and creative answers but my suggetion is to make your methods paramterized and that should solve all your problems without any tricks.
if you have function:
function A()
{
var val = external_value_from_query_string_or_global_param;
}
you can change this to:
function B(function_param)
{
var val = function_param;
}
I think this is most natural approach, you don't need to crate extra documentation about 'file parameters' and you receive the same. This specially useful if you allow other developers to use your js file.
It's not valid html (I don't think) but it seems to work if you create a custom attribute for the script tag in your webpage:
<script id="myScript" myCustomAttribute="some value" ....>
Then access the custom attribute in the javascript:
var myVar = document.getElementById( "myScript" ).getAttribute( "myCustomAttribute" );
Not sure if this is better or worse than parsing the script source string.
Here i have found an another way of doing this same thing. In the reuired js file [cttricks.js as i have used it for testing, you can have your any .js file], we'll simply list up all script elements and get the required one as it is always going to be at last index. And then get ".attributes.src.value" from that.
Now, in any case of script call, it is
<script src="./cttricks.js?data1=Hello&data2=World"></script>
And in the cttricks.js script file,
var scripts = document.getElementsByTagName('script');
var jsFile = new URL("http://" + scripts[scripts.length-1].attributes.src.value);
/*get value from query parameters*/
console.log(jsFile.searchParams.get("data1"));
console.log(jsFile.searchParams.get("data2"));
Enjoy!!
No, you cant really do this by adding variables to the querystring portion of the JS file URL. If its writing the portion of code to parse the string that bothers you, perhaps another way would be to json encode your variables and put them in something like the rel attribute of the tag? I don't know how valid this is in terms of HTML validation, if thats something you're very worried about. Then you just need to find the rel attribute of the script and then json_decode that.
eg
<script type='text/javascript' src='file.js' rel='{"myvar":"somevalue","anothervar":"anothervalue"}'></script>
If you need a way that passes CSP check (which prohibits unsafe-inline) then you have to use nonce method to add a unique value to both the script and the CSP directive or write your values into the html and read them again.
Nonce method for express.js:
const uuidv4 = require('uuid/v4')
app.use(function (req, res, next) {
res.locals.nonce = uuidv4()
next()
})
app.use(csp({
directives: {
scriptSrc: [
"'self'",
(req, res) => `'nonce-${res.locals.nonce}'` // 'nonce-614d9122-d5b0-4760-aecf-3a5d17cf0ac9'
]
}
}))
app.use(function (req, res) {
res.end(`<script nonce="${res.locals.nonce}">alert(1 + 1);</script>`)
})
or write values to html method. in this case using Jquery:
<div id="account" data-email="{{user.email}}"></div>
...
$(document).ready(() => {
globalThis.EMAIL = $('#account').data('email');
}
Although this question has been asked a while ago, it is still relevant as of today. This is not a trivial approach using script file params, but I already had some extreme use-cases that this way was most suited.
I came across this post to find out a better solution than I wrote a while ago, with hope to find maybe a native feature or something similar.
I will share my solution, up until a better one will be implemented. This works on most modern browsers, maybe even on older ones, didn't try.
All the solutions above, are based on the fact that it has to be injected with predefined and well marked SCRIPT tag and rely completely on the HTML implementation. But, what if the script is injected dynamically, or even worse, what if you are write a library, that will be used in a variety of websites?
In these and some other cases, all the above answers are not sufficient and even becoming too complicated.
First, let's try to understand what do we need to achieve here. All we need to do is to get the URL of the script itself, from there it's a piece of cake.
There is actually a nice trick to get the script URL from the script itself. One of the functionalities of the native Error class, is the ability to provide a stack trace of the "problematic location", including the exact file trace to the last call. In order to achieve this, I will use the stack property of the Error instance, that once created, will give the full stack trace.
Here is how the magic works:
// The pattern to split each row in the stack trace string
const STACK_TRACE_SPLIT_PATTERN = /(?:Error)?\n(?:\s*at\s+)?/;
// For browsers, like Chrome, IE, Edge and more.
const STACK_TRACE_ROW_PATTERN1 = /^.+?\s\((.+?):\d+:\d+\)$/;
// For browsers, like Firefox, Safari, some variants of Chrome and maybe other browsers.
const STACK_TRACE_ROW_PATTERN2 = /^(?:.*?#)?(.*?):\d+(?::\d+)?$/;
const getFileParams = () => {
const stack = new Error().stack;
const row = stack.split(STACK_TRACE_SPLIT_PATTERN, 2)[1];
const [, url] = row.match(STACK_TRACE_ROW_PATTERN1) || row.match(STACK_TRACE_ROW_PATTERN2) || [];
if (!url) {
console.warn("Something went wrong. You should debug it and find out why.");
return;
}
try {
const urlObj = new URL(url);
return urlObj.searchParams; // This feature doesn't exists in IE, in this case you should use urlObj.search and handle the query parsing by yourself.
} catch (e) {
console.warn(`The URL '${url}' is not valid.`);
}
}
Now, in any case of script call, like in the OP case:
<script type="text/javascript" src="file.js?obj1=somevalue&obj2=someothervalue"></script>
In the file.js script, you can now do:
const params = getFileParams();
console.log(params.get('obj2'));
// Prints: someothervalue
This will also work with RequireJS and other dynamically injected file scripts.
I think it is far more better and modern solution to just use localStorage on the page where the javascript is included and then just re-use it inside the javascript itself. Set it in localStorage with:
localStorage.setItem("nameOfVariable", "some text value");
and refer to it inside javascript file like:
localStorage.getItem("nameOfVariable");
It's possible to pass parameters to js modules and read them after via import.meta.url.
For example, with the following HTML
<script type="module">
import './index.mjs?someURLInfo=5';
</script>
the following JavaScript file will log the someURLInfo parameter:
// index.mjs
new URL(import.meta.url).searchParams.get('someURLInfo'); // 5
The same applies when a file imports another:
// index.mjs
import './index2.mjs?someURLInfo=5';
// index2.mjs
new URL(import.meta.url).searchParams.get('someURLInfo'); // 5

Finding javascript's origin

Is it possible from a Javascript code to find out "where" it came from?
I needed this to provide scripts that could run folder-agnostic, e.g.:
http://web1/service-a/script.js
http://web2/some-folder/service-b/script.js
And they're linked in:
http://web1/page1.html
http://web2/page2.html
The file script.js is identical in both locations but I would like them to be able to find out where it originates from so it can call the right web service methods (script.js from service-a should call service-a.method while script.js that is served from service-b should call service-b.method)
Is there a way to find out where script.js came from without using any server-side code?
Well, it's kind of a hack, you could grab all the <script> tags in the document, look at which one has the file name of the file, and do the logic from there.
document.getElementsByTagName('script'); is pretty much all you need. The rest is basic JS.
Even more interesting than looping through all of the returned elements (although that's probably safest), is that we can simply only look at the last element returned by the call above, as Javascript guarantees that must be the <script> tag we're in at the time of it being parsed (with the exception of deferred scripts). So this code:
var all_scripts = document.getElementsByTagName('script');
var current_script = scripts[all_scripts.length-1];
alert(current_script.src);
Will alert the source of the script tag used to include the current Javascript file.
You can analyze source of the html where script.js is included for tag and retrieve path of the script.js from there. Include next function in script.js and use it to retrieve the path.
function getPath() {
var path = null;
var scriptTags = document.getElementsByTagName("script");
for (var i = 0; i < scriptTags.length; i++) {
var scriptTagSrc = scriptTags.item(i).src;
if (scriptTagSrc && scriptTagSrc.indexOf("script.js") !== -1) {
path = scriptTagSrc;
break;
}
}
return path;
}

Categories

Resources