I have written a script which I have in the head section on my landing pages. What it does is that it loads a facebook pixel which I have stored in another part of my application which I access by calling an endpoint. This because I need to dynamically change the script without interfering with the code on the landing page itself. This code is written in Jquery but now I need jQuery gone from my application so I've tried to rewrite it using only vanilla javascript.
The problem is that it works just fine with the jQuery code, but when I've tried to replace it with vanilla Javascript it does not seem to inject the code in the correct way. The output in the DOM looks exactly the same but it does not fire the pixel somehow.
So my question is. Why is this?
Here is the working example of my jQuery script
<script>
$.get('https://api.mydomain.com/script', function (data) {
$('head').append(data);
});
</script>
Here is my vanilla Javascript version
<script>
var theUrl = 'https://api.mydomain.com/script';
let xhr = new XMLHttpRequest();
xhr.open("GET", theUrl);
xhr.send();
xhr.onload = function() {
document.querySelector("head").insertAdjacentHTML("beforeend", xhr.response);
};
</script>
I think the issue is with insertAdjacentHTML - just a guess, but maybe it only works for HTML (divs, images, etc.) rather than scripts. Hopefully this workaround is an acceptable solution:
(function() {
const
exampleScript = getScriptContent(`
<script>
alert("example script loaded");
<\/script>
`),
s = document.createElement("script"),
t = document.createTextNode(exampleScript);
s.appendChild(t);
document.getElementsByTagName("head")[0].appendChild(s);
function getScriptContent(htmlStr) {
const tempDiv = document.createElement("div");
tempDiv.innerHTML = htmlStr;
return tempDiv.innerText;
}
})();
This is a very common question in here related to AJAX, but I can't seem to find one for my case, because most of them used jQuery, and other reasons. Probably mine isn't efficient/recommended, but either way, here we go.
I have a button [let's say we have a reference to it for the sake of it called btn].
It listens for a clicking event. When the user clicks the button, it makes an AJAX request to a .txt file present in the same directory the main HTML/CSS/JS file is. Let's call it test.txt.
Now, it changes the <html>'s innerHTML(not the head/body, the html), and the innerHTML is the response from the AJAX request.
test.txt holds HTML code. And within that HTML code there's <script src="another-js-file.js">.
This doesn't get executed, this is the problem.
Before you scream at me INNERHTML DOESN'T EXECUTE ANY SCRIPTS I know that. I've seen other answers saying to create a <script> tag within a div that's within yet another div, but it doesn't seem to work with external js files, and the solutions indeed used innerHTML.
Okay, here's a sketch:
btn.onclick = function(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState = XMLHttpRequest.DONE){
document.documentElement.innerHTML = this.responseText;
}
}
xhr.open("GET", "./test.txt");
xhr.send();
}
Where test.txt holds:
<head>
<title>Document</title>
<link rel="stylesheet" href="test.css">
<script src="another-js-file.js"></script>
</head>
<body>
<h1>Hello World!</h1>
</body>
No jQuery.
I found that by creating a script element and setting its source to "another-file.js" like this worked:
var script = document.createElement("script");
script.src = "test.js";
document.body.appendChild(script);
THIS GOES AFTER document.documentElement.innerHTML = this.responseText;
I noticed in your initial XHR request you wrote:
if(xhr.readyState = XMLHttpRequest.DONE)
This should actually be triple === not the single one.
Add this function to your initial JS file where you make the XHR request,
function setInnerHtml(el, html) {
el.innerHTML = html;
// Get all the scripts from the new HTML
const scripts = el.querySelectorAll('script');
// Loop through all the scripts
for (let i = 0; i < scripts.length; i++)
{
// Create a new script
const s = document.createElement('script');
// Go through all the attributes on the script
for (let j = 0; j < scripts[i].attributes.length; j++) {
const a = scripts[i].attributes[j];
// Add each attribute to the new script
s.setAttribute(a.name, a.value);
}
// Incase there is code inside the script tag
// Example: <script>alert</script>
s.innerHTML = scripts[i].innerHTML;
// Append the new script to the head (you could change this to the end of the body as well)
document.head.appendChild(s);
}
}
Then when you go to set the innerHTML of the root document object, use the above function instead.
if(xhr.readyState === XMLHttpRequest.DONE){
setInnerHtml(document.documentElement, this.responseText);
}
I want to read a file that's saved in the same folder. Then I want to show its content in a div in index.html. The problem: when I used require("fs") it didn't work since it wasn't running server-side. I have been looking around and can't find a simple answer. I want to make my website a little dynamic, so here is the code that should fire upon a button click:
function videos() {
var body = *read a file("insertfilename")*;
console.log(body);
document.getElementById("body").innerHTML = body;
}
"body" in this case is just the id I gave the div.
!EDIT!
Now to explain it further. I want to use it as my main website. When I go onto there it should open an empty html file, which has a scriptfile as source. "onload" it should read a file , which is also already on the server, and put its content into a div inside of the body. If I click on a hotlink or a Button, it should read another file and put that content into that div instead. Maybe that gives a little clarification on what I am trying to do. I dont want to reload to open other sites of mine.
Seems like you need some basic file fetching since you are not using a server. Have you tried FileReader for javascript? It is a very simple and straightforward object. The example on the page seems similar to what you are trying to accomplish, except you want to fetch the file, not the user.
You can use AJAX. It stands for Asynchronous JavaScript And XML. You can send asynchronous requests to server with it. Just make sure that file that you are requesting is on the same domain as JS file.
function videos() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() { //this will execute when you receive response from the server
if (this.readyState == 4 && this.status == 200) {
document.getElementById("body").innerHTML = this.responseText;
console.log(this.responseText)
}
};
xhttp.open("GET", "filename.txt", true);
xhttp.send();
}
Here is W3schools tutorial if you want to learn more.
If I have a script tag like this:
<script
id = "myscript"
src = "http://www.example.com/script.js"
type = "text/javascript">
</script>
I would like to get the content of the "script.js" file. I'm thinking about something like document.getElementById("myscript").text but it doesn't work in this case.
tl;dr script tags are not subject to CORS and same-origin-policy and therefore javascript/DOM cannot offer access to the text content of the resource loaded via a <script> tag, or it would break same-origin-policy.
long version:
Most of the other answers (and the accepted answer) indicate correctly that the "correct" way to get the text content of a javascript file inserted via a <script> loaded into the page, is using an XMLHttpRequest to perform another seperate additional request for the resource indicated in the scripts src property, something which the short javascript code below will demonstrate. I however found that the other answers did not address the point why to get the javascript files text content, which is that allowing to access content of the file included via the <script src=[url]></script> would break the CORS policies, e.g. modern browsers prevent the XHR of resources that do not provide the Access-Control-Allow-Origin header, hence browsers do not allow any other way than those subject to CORS, to get the content.
With the following code (as mentioned in the other questions "use XHR/AJAX") it is possible to do another request for all not inline script tags in the document.
function printScriptTextContent(script)
{
var xhr = new XMLHttpRequest();
xhr.open("GET",script.src)
xhr.onreadystatechange = function () {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
console.log("the script text content is",xhr.responseText);
}
};
xhr.send();
}
Array.prototype.slice.call(document.querySelectorAll("script[src]")).forEach(printScriptTextContent);
and so I will not repeat that, but instead would like to add via this answer upon the aspect why itthat
Do you want to get the contents of the file http://www.example.com/script.js? If so, you could turn to AJAX methods to fetch its content, assuming it resides on the same server as the page itself.
Update: HTML Imports are now deprecated (alternatives).
---
I know it's a little late but some browsers support the tag LINK rel="import" property.
http://www.html5rocks.com/en/tutorials/webcomponents/imports/
<link rel="import" href="/path/to/imports/stuff.html">
For the rest, ajax is still the preferred way.
I don't think the contents will be available via the DOM. You could get the value of the src attribute and use AJAX to request the file from the server.
yes, Ajax is the way to do it, as in accepted answer. If you get down to the details, there are many pitfalls. If you use jQuery.load(...), the wrong content type is assumed (html instead of application/javascript), which can mess things up by putting unwanted <br> into your (scriptNode).innerText, and things like that. Then, if you use jQuery.getScript(...), the downloaded script is immediately executed, which might not be what you want (might screw up the order in which you want to load the files, in case you have several of those.)
I found it best to use jQuery.ajax with dataType: "text"
I used this Ajax technique in a project with a frameset, where the frameset and/or several frames need the same JavaScript, in order to avoid having the server send that JavaScript multiple times.
Here is code, tested and working:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html>
<head>
<script id="scriptData">
var scriptData = [
{ name: "foo" , url: "path/to/foo" },
{ name: "bar" , url: "path/to/bar" }
];
</script>
<script id="scriptLoader">
var LOADER = {
loadedCount: 0,
toBeLoadedCount: 0,
load_jQuery: function (){
var jqNode = document.createElement("script");
jqNode.setAttribute("src", "/path/to/jquery");
jqNode.setAttribute("onload", "LOADER.loadScripts();");
jqNode.setAttribute("id", "jquery");
document.head.appendChild(jqNode);
},
loadScripts: function (){
var scriptDataLookup = this.scriptDataLookup = {};
var scriptNodes = this.scriptNodes = {};
var scriptNodesArr = this.scriptNodesArr = [];
for (var j=0; j<scriptData.length; j++){
var theEntry = scriptData[j];
scriptDataLookup[theEntry.name] = theEntry;
}
//console.log(JSON.stringify(scriptDataLookup, null, 4));
for (var i=0; i<scriptData.length; i++){
var entry = scriptData[i];
var name = entry.name;
var theURL = entry.url;
this.toBeLoadedCount++;
var node = document.createElement("script");
node.setAttribute("id", name);
scriptNodes[name] = node;
scriptNodesArr.push(node);
jQuery.ajax({
method : "GET",
url : theURL,
dataType : "text"
}).done(this.makeHandler(name, node)).fail(this.makeFailHandler(name, node));
}
},
makeFailHandler: function(name, node){
var THIS = this;
return function(xhr, errorName, errorMessage){
console.log(name, "FAIL");
console.log(xhr);
console.log(errorName);
console.log(errorMessage);
debugger;
}
},
makeHandler: function(name, node){
var THIS = this;
return function (fileContents, status, xhr){
THIS.loadedCount++;
//console.log("loaded", name, "content length", fileContents.length, "status", status);
//console.log("loaded:", THIS.loadedCount, "/", THIS.toBeLoadedCount);
THIS.scriptDataLookup[name].fileContents = fileContents;
if (THIS.loadedCount >= THIS.toBeLoadedCount){
THIS.allScriptsLoaded();
}
}
},
allScriptsLoaded: function(){
for (var i=0; i<this.scriptNodesArr.length; i++){
var scriptNode = this.scriptNodesArr[i];
var name = scriptNode.id;
var data = this.scriptDataLookup[name];
var fileContents = data.fileContents;
var textNode = document.createTextNode(fileContents);
scriptNode.appendChild(textNode);
document.head.appendChild(scriptNode); // execution is here
//console.log(scriptNode);
}
// call code to make the frames here
}
};
</script>
</head>
<frameset rows="200pixels,*" onload="LOADER.load_jQuery();">
<frame src="about:blank"></frame>
<frame src="about:blank"></frame>
</frameset>
</html>
related question
.text did get you contents of the tag, it's just that you have nothing between your open tag and your end tag. You can get the src attribute of the element using .src, and then if you want to get the javascript file you would follow the link and make an ajax request for it.
In a comment to my previous answer:
I want to store the content of the script so that I can cache it and use it directly some time later without having to fetch it from the external web server (not on the same server as the page)
In that case you're better off using a server side script to fetch and cache the script file. Depending on your server setup you could just wget the file (periodically via cron if you expect it to change) or do something similar with a small script inthe language of your choice.
if you want the contents of the src attribute, you would have to do an ajax request and look at the responsetext. If you where to have the js between and you could access it through innerHTML.
This might be of interest: http://ejohn.org/blog/degrading-script-tags/
I had a same issue, so i solve it this way:
The js file contains something like
window.someVarForReturn = `content for return`
On html
<script src="file.js"></script>
<script>console.log(someVarForReturn)</script>
In my case the content was html template. So i did something like this:
On js file
window.someVarForReturn = `<did>My template</div>`
On html
<script src="file.js"></script>
<script>
new DOMParser().parseFromString(someVarForReturn, 'text/html').body.children[0]
</script>
You cannot directly get what browser loaded as the content of your specific script tag (security hazard);
But
you can request the same resource (src) again ( which will succeed immediately due to cache ) and read it's text:
const scriptSrc = document.querySelector('script#yours').src;
// re-request the same location
const scriptContent = await fetch(scriptSrc).then((res) => res.text());
If you're looking to access the attributes of the <script> tag rather than the contents of script.js, then XPath may well be what you're after.
It will allow you to get each of the script attributes.
If it's the example.js file contents you're after, then you can fire off an AJAX request to fetch it.
It's funny but we can't, we have to fetch them again over the internet.
Likely the browser will read his cache, but a ping is still sent to verify the content-length.
[...document.scripts].forEach((script) => {
fetch(script.src)
.then((response) => response.text() )
.then((source) => console.log(source) )
})
Using 2008-style DOM-binding it would rather be:
document.getElementById('myscript').getAttribute("src");
document.getElementById('myscript').getAttribute("type");
You want to use the innerHTML property to get the contents of the script tag:
document.getElementById("myscript").innerHTML
But as #olle said in another answer you probably want to have a read of:
http://ejohn.org/blog/degrading-script-tags/
If a src attribute is provided, user agents are required to ignore the content of the element, if you need to access it from the external script, then you are probably doing something wrong.
Update: I see you've added a comment to the effect that you want to cache the script and use it later. To what end? Assuming your HTTP is cache friendly, then your caching needs are likely taken care of by the browser already.
I'd suggest the answer to this question is using the "innerHTML" property of the DOM element. Certainly, if the script has loaded, you do not need to make an Ajax call to get it.
So Sugendran should be correct (not sure why he was voted down without explanation).
var scriptContent = document.getElementById("myscript").innerHTML;
The innerHTML property of the script element should give you the scripts content as a string provided the script element is:
an inline script, or
that the script has loaded (if using the src attribute)
olle also gives the answer, but I think it got 'muddled' by his suggesting it needs to be loaded through ajax first, and i think he meant "inline" instead of between.
if you where to have the js between and you could access it through innerHTML.
Regarding the usefulness of this technique:
I've looked to use this technique for client side error logging (of javascript exceptions) after getting "undefined variables" which aren't contained within my own scripts (such as badly injected scripts from toolbars or extensions) - so I don't think it's such a way out idea.
Not sure why you would need to do this?
Another way round would be to hold the script in a hidden element somewhere and use Eval to run it. You could then query the objects innerHtml property.
I am currently contracted to a place that cannot use a CMS or PHP, but they want me to build something like a CMS using HTML and JavaScript.
I know it sounds ridiculous but I do not want to be searching for another job these days and they are the nicest people that I have ever worked for - EVER - and I old.
One of the concepts of a CMS is to have global files that you can include at any given time.
As a result, I tried the $.ajax, $.get, etc..., but I was running into issues of Access URI denied and those kind of things for trying to load a file which is one directory level the current directory.
I was able to get the javascript file to load by using the old XMLHttpRequest/ActiveXObject.
However, the script within the div that has been loaded cannot be called. I receive an error of "Can't find variable: mFunc" which is the name of the function that has been loaded into the div.
Here's the code for my html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>retrieve local file one level up</title>
<script type="text/javascript">
<!--
var createRequestObject = function(){
var req;
if(window.XMLHttpRequest){
// Firefox, Safari, Opera...
req = new XMLHttpRequest();
}else if(window.ActiveXObject){
// Internet Explorer 5+
req = new ActiveXObject("Microsoft.XMLHTTP");
}else{
alert('There was a problem creating the XMLHttpRequest object');
}
return req;
}
// Make the XMLHttpRequest object
var http = createRequestObject();
var sendRequestPost = function(){
var jscript = '../test.js';
// Open PHP script for requests
http.open('GET', jscript);
http.setRequestHeader('Content-Type', 'text/javascript');
http.onreadystatechange = handleResponsePost;
http.send(null);
var mT = setTimeout("mFunc()", 2000);
}
var handleResponsePost = function(){
if(http.readyState == 1){
document.getElementById('mDiv').innerHTML = "Please wait, loading... " ;
}else if(http.readyState == 4 && http.status == 200){
// Text returned from PHP script
var response = http.responseText;
document.getElementById('mDiv').innerHTML = response;
if(response){
// Update ajaxTest2 content
document.getElementById('mDiv').innerHTML = response;
}
}else if(http.readyState == 2){
document.getElementById('mDiv').innerHTML = http.responseText;
}else if(http.readyState == 3){
document.getElementById('mDiv').innerHTML = http.responseText;
}
}
-->
</script>
</head>
<body onload="javascript:sendRequestPost();">
<div id="mDiv"></div>
</body>
</html>
Here is the javascript that loads just fine into mDiv:
<script type="text/javascript">
<!--
var mFunc = function(){
var mScript = document.createElement("script");
mScript.setAttribute("type","text/javascript");
var data = 'alert("gets here");'
mScript.text = data;
var head = document.getElementsByTagName("head")[0];
head.appendChild(mScript);
}
-->
</script>
Yet, after the two seconds have passed, I receive the error.
I am sure that it is probably because the browser just sees this as text within the div, so how do I make it recognize that it is javascript.
I have tried using eval, which I do not want to use, but even returns a parse error.
Thanks in advance
../ has meaning to the local filesystem (on most platforms), but not to HTML or to most webservers. Remember that the URL is just a query string for the server.
Generally speaking, you need to parse the URL to remove the undesired few elements. If you just want scripts that are common across the website, though, they should be referenced from the root, so the relative URL would begin with /.
A quick hack would be /(.*)\/.*/.exec( '/foo/bar/baz.html' )[1]. This doesn't handle the query string following ? or anchor following # but you won't have a query on a static website, and won't have anchors until you get into more advanced techniques. jQuery has a better utility for parsing URLs, also based on regexps.
It's offtopic for this site, but you will have to be very familiar with XHR to implement a JavaScript CMS.
OK, another programmer that I work with, has found a simple solution.
Instead trying to use ajax to load a JavaScript file from a higher directory level and then run a document.writeln or document.getElementById("someDiv").innerHTML -- reverse the steps.
Include the JS file as you would normally:
<script type="text/javascript" src="../../common/header.js"></script>
Within this JS file
function CommonHeader(mPath) {
document.writeln('<header>');
document.writeln(' <div class="PageWidth">');
document.writeln(' <h1>Something<sup>®</sup> <em>Learn about us</em></h1>');
document.writeln(' <nav>');
document.writeln(' <ul>');
document.writeln(' <li id="loginOut"></li>');
The order needs to be for you to call document.writeln at the beginning of the process.
We can now load header.js, footer.js, and whatever other file that we wish to load, along with having an array at the top of each page denoting the path to those files, for lower directory level htmls
dynamicPathArr[0] = "../../";
Then within whatever file, you can call the function to write the date into the page
<script type="text/javascript">CommonHeader(dynamicPathArr[0])</script>
I cannot believe that I did not think of this completely simple solution.
Although this is not SEO friendly, it is good for only updating header, footer, nav, etc... in one location, until everything is finalized.
And thanks you for the response