So I have a problem where I need to get the entirety of a script's source code as a string (whether it's an inline script or a script that uses the src attribute) from within the script itself, but without knowing beforehand exactly what script it is. I can't just do an XHR for that reason. Several scripts on the page will listen for events, and when they handle them they will also run code that identifies the script's own source code. How should I do this?
function identifySelf() {
// Some code here
return mysource; // should return the source code of the script in which this function is defined
}
You will need to identify each script tag with an id. Then
var script=document.getElementById("my_id");
var content=script.innerHTML || "";
if(content==null || content==""){
var src=script.src;
// ajax in the script, I'm not going to write the code because I'm on mobile
// I'm assuming you can write it yourself
}
EDIT: sorry, I didn't read your question fully. If you need to return the content right away, you will need to ajax in scripts' content on page load, and the return cached content. There is no way to just get the innerHTML like that.
Related
Suppose I go
$( '#' + subform_id ) .load( "subform.php" );
where '#' + subform_id is the ID of a DIV
... is there any way the PHP in subform.php can find out, within its PHP code, the identity of the DIV? (e.g. using its own JS code <script> section)
Or otherwise refer to it by some mechanism without knowing its ID? (e.g. to use JQ's append())
Obviously I could pass the subform_id as a param of the data object (2nd param of load()). But I'm just wondering...
later
followed up on what I thought Victor2748 was suggesting... but in fact it was the ID of a <SCRIPT> block in the injected file which I used to gain access to the existing JS DOM.
Victor2748: if you read this, I'm not sure how you could know the "id of the parent container of your subform.php page" without somehow passing this id as a param in the load() function's data object...
even later
Every comment in this thread says something intelligent! In fact, concerning the question of specifying that this is a PHP file, I'm still trying to get my head around something: obviously it is possible to access the DOM when JS runs in the client. But if your PHP code needs to know the name of the DIV into which it's being loaded I believe you do indeed have to pass this through _POST or _GET. I think there are many reasons why injected PHP code might need this sort of info, e.g. so it can contain code which at some point injects more PHP into the same DIV...
Although... clearly that injection code will inevitably use a JS/JQ script, so maybe that would be the appropriate time to find out what you need about where you are in the DOM.
In JavaScript, you can use this.parentNode to get the parent container, and use this.parentNode.id to get the parent div's id.
Here is an example how your loaded block can get itself as an object/node:
var loadedBlock = document.getElementById("nameOfYourDownloadedParentContainer")
Then you can use loadedBlock.parentNode to get its parent element, then you can get any parameter from it, to identify the element/div.
Update:
First you need to get the node of the current executing <script> tag:
var arrScripts = document.getElementsByTagName('script');
var currentScriptTag = arrScripts[arrScripts.length - 1];
Then, to get the parent of the script tag, use: currentScriptTag.parentNode
(I did not test it yet, please tell me if it helped)
I think so... if you have a script tag in subform.php and the file has the following HTML: Submit form, you should be able to:
var subformId = $('#mydiv').parent().id;
It would work because the script tag executes when the PHP file is included. Put the script tag at the end of subform.php to be sure.
Why does a linked JavaScript file sometimes not work when it is included at the top of the page and not at the bottom?
<script type="text/javascript" src"..."></script>
For example, if you want to manipulate DOM items, and those are not yet existing, it won't work. If the JavaScript file is included in the head, the body is not existing yet, but if you include it at the end of the body, those items are valid.
If you don't want to rely on this behaviour, you may define a callback, which is run, when the document is ready, i.e. when the whole of the DOM is loaded already.
This is what e.g. jQuery achieves with $(document).ready(function() {}), or more shortly $(function () {});. In vanilla JavaScript (using modern browsers, so IE9+) this can be achieved using
document.addEventListener("DOMContentLoaded", function() {
// code...
});
The best way to know why is it not working is by checking for JS error. Try to find out what errors you are getting when the script has been included at the top. As mentioned in the other response it can be because of DOM items. You can circumvent this issue by adding a "defer" tag to the script.
It can also be because of some JS object you are expecting to be present when this script runs. For example if your script tag is serving a JSONP request then you must have the function that processes the data. Otherwise you will get a "undefined function" error when the script runs.
JS code is executed instruction by instruction from top to bottom.
The code that calls a function needs to be under that functions definition.
This code works:
var func = function()
{
alert('it works');
};
func();
While this doesn't:
func();
var func = function()
{
alert('it works');
};
It throws an undefined error. The reason for this is that JS compiler is not aware of the func definition at the time it tries to call it.
Same goes for the JS files included in your HTML page. You can include them at the bottom as long as there are not dependencies in above sections, or, if they do not try to manipulate HTML code before page load.
I am working on a project that uses AJAX to download HTML, CSS and Javascript in one singe chunk of text then appends it to an element on the page. Here is the code:
_t.stage.empty();
_t.stage.html(DATA);
This works fine.
Here is the problem:
After adding the HTML to the stage, I call this function:
if(initApp != null && typeof(initApp) == "function") initApp();// Checks for initApp(). If exists, executes.
If I load a page that has this function, then load one that does NOT have this function, the function from the first page is executed. Here is some psuedo code to understand the results.
page 1:
This is a page.
<style>...</style>
<script> function initApp(){ alert("hello"); } </script>
When this page is run, an alert box with the text 'hello' is shown.
page 2: (no initApp() function)
This is page 2.
<style>...</style>
When the page is run, an alert box with the text 'hello' is shown.
Please note: These pages are loaded with AJAX and inserted into the HTML of an already loaded page.
It is not easy to tell exactly what you're trying to do, but if what you're trying to do is make it so that some other code that calls initApp() will cause nothing to happen when it calls that, then you can simply redefine the function to a do-nothing function like this:
initApp = function() {}
The most recent definition of a function takes precedence (e.g. replaces any prior definitions).
If your newly loaded code contains an implementation of initApp() that you don't want called the second time the script is loaded, then you're out of luck. You can't stop that. You will need to change the structure of your code so that the dynamically loaded code doesn't execute stuff you don't want to be executed. There are many different ways you could do that. For example, you could have a global boolean that keeps track of whether the init code has been called yet.
var initCalled = false;
function initApp() {
if (!initCalled) {
initCalled = true;
// rest of initialization code here
}
}
initApp(); // will only actually do anything the first time it's called
// even if it is loaded more than once
It appears from the comments that you seem to think that reloading a script tag with different code will somehow make code from the previous script go away. It will not. Once a function is loaded, it stays loaded unless it is redefined to mean something else or unless some code explicitly removed a property from an object. It does not matter how the code was loaded or whether it was in the core page or an external script file.
Javascript functions that no longer exist
This is a bad premise. The functions still exist, which is obvious from the fact that the second AJAX load ended up executing it. The fact that the <script> tags are replaced and no longer in the document doesn't undefine the function. It's like asking why is your TV still broken if the burglar that broke it is no longer there.
There are two basic things you can do:
a) Clear the function explicitly yourself:
if (initApp != null && typeof(initApp) == "function") {
initApp();
delete window.initApp;
}
b) Change the function name to be unique per AJAX page (or namespace the function with the same idea), probably tied to the name of the AJAX page, so you can invoke it in a more specific manner.
I know that I can run an external Javascript file from within HTML with the following syntax:
<script type="text/javascript"
src="http://somesite.com/location/of/javascript.js">
</script>
This will result in http://somesite.com/location/of/javascript.js being run the moment the browser reads that line of the HTML.
But is there a way I can run an external Javascript file from within Javascript? Something like:
if (x == 1)
{
run this! -> http://somesite.com/location/of/javascript.js;
}
Obviously that's not valid code. But I can't find any example of what might be the right way to do this (if it exists), because all the help text I find with Google searches tell me how to run Javascript from within HTML
I know that I can include a Javascript file and then call functions within it. However, in this situation, I do not have any control over http://somesite.com/location/of/javascript.js, and it is designed to execute the moment it is called. I can't change how it works, so I need to figure out how to call it at the right time in the right way.
Is there a way I can get it to be called and executed immediately depending on a conditional statement?
Yes, in Pure Javascript you can Load javascript dynamically
var s = document.createElement("script");
s.src = "test.js";
document.body.appendChild(s);
There is a way...
var extfile = document.createElement('script')
extfile.setAttribute("type","text/javascript")
extfile.setAttribute("src", external_jsfilename)
document.getElementsByTagName("head")[0].appendChild(extfile)
Simple as that ....
Use jQuery's .getScript() the file will be loaded and then executed
if (x == 1)
{
$.getScript( "http://somesite.com/location/of/javascript.js");
}
I have a javascript function I'm writing which is being used to include an external JS file, but only once. The reason I need such a function is because it is being called when some content is loaded via AJAX and I need to run page-specific code to that content (no, just using .live won't cover it).
Here's my attempt, shortened for brevity:
$.include_once = function(filename) {
if ($("script[src='" + filename + "']").length === 0) {
var $node = $("<script></script>")
.attr({
src : filename,
type : "text/javascript"
})
;
$(document.body).append($node);
}
};
This works fine: the function is called, it loads the external file, and that file is being run when loaded. Perfect.
The problem is that it will always re-load that external file: the query I'm using to check for the presence of the script always finds nothing!
When debugging this, I added some lines:
alert($("script").length); // alerts: 4
$(document.body).append($node);
alert($("script").length); // alerts: 4
Looking in the dynamic source (the HTML tab of Firebug), I can't find the script tag at all.
I know that I could maintain an array of files that I've previously included, but I was hoping to go with a method such as this, which (if it worked), seems a bit more robust, since not all the JS files are being included in this way.
Can anyone explain the behaviour seen in this second snippet?
jQuery is a bit of a dumb-dumb in this case; it doesn't do at all what you'd expect. When you append($node) jQuery does this:
jQuery.ajax({
url: $node.src,
async: false,
dataType: "script"
})
Woops! For local files (eg on the same domain) jQuery performs a standard XMLHttpRequest for the .js file body, and proceeds to "eval" it by a whole convoluted process of creating a <script> tag (again!) and settings it's contents to your .js file body. This is to simulate eval but in the global context.
For cross-domain files, since it cannot perform the standard XMLHttpRequest due to the same-domain policy, jQuery once again creates a <script> element and inserts it into <head>.
In both the local and cross-domain cases above jQuery finally gets around to doing this:
head.removeChild(script);
And booms your .length check! Bummer.
So on to your problem, don't bother jQuery with this. Just do
document.getElementsByTagName('head')[0]
.appendChild(
document.createElement('script')
)
.src = filename;
Which will do what you'd expect, particularly wrt querying for it later.
You're trying to solve a problem that has already been solved several times over. Try LazyLoad for example. There are also similar plugins for jQuery.
Instead of setting the source attribute of the script-tag, set the "text" attribute of the script tag. This works in all modern browsers (the application where I use that in practice does not support IE6, so I do not know about this creep...).
In practice it would look like this (you HAVE TO add code to omit double inclusion on yourself - e.g. a simple array of all alread loaded scripts, though thats very application specific, and why should you anyway load code twice? try to omit double-loading code...!):
var script_source_code_string = <some dynamically loaded script source code>;
var $n = $("<script></script>");
$n.get(0).text = script_source_code_string;
$(document.body).append($n);
Or even simpler (without jquery, my code at this stage does not know jquery, it may also be loaded dynamically):
var script_source_code_string = <some dynamically loaded script source code>;
var s = document.createElement('script');
document.getElementsByTagName('head')[0].appendChild(s);
s.text = script_source_code_string;