add script dynamically to DOM before other scripts are executed - javascript

I do a simple check if js file exists. If not, I try to load it dynamically before other scripts from bottom of a page are loaded. Is it possible to do? Here is fiddle where bottom script is executed before thus giving errors.
https://jsfiddle.net/vnfxus56/1/
thank you.
<div id="top">top</div>
<script>
doesFileExist('https://ajax.googleapis.com/ajax/libs/nonexistingfile.js');
function doesFileExist(urlToFile) {
var xhr = new XMLHttpRequest();
xhr.open('HEAD', urlToFile, false);
xhr.send();
if (xhr.status == "404") {
console.log("File doesn't exist");
var script = document.createElement('script')
script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js'
document.head.append(script)
return false;
} else {
console.log("File exists");
return true;
}
}
</script>
<script>
//this is printed out of a variable as a bunch of inline jquery code
$("#top").fadeOut();
</script>

below I posted the code that could await until the "xhr" request is finished. I used the "async functions" concept in javascript that you can read more about it here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
function afterLoad() {
console.log('DOM fully loaded and parsed');
$("#top").fadeOut();
}
#top {
background-color: green;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>xhr</title>
<link rel="stylesheet" href="style.css">
</head>
<body onload="afterLoad()">
<!-- using "onload" method is necessary to run the script after finishing "xhr" -->
<div id="top">top</div>
<script>
let urlToFile = 'https://ajax.googleapis.com/ajax/libs/nonexistingfile.js';
function doesFileExist(urlToFile) {
return new Promise(resolve => {
var xhr = new XMLHttpRequest();
xhr.open('HEAD', urlToFile, false);
xhr.send();
if (xhr.status == "404") {
console.log("File doesn't exist");
var script = document.createElement('script');
script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js';
script.setAttribute("async", "");
console.log(script);
document.body.append(script);
// your custom script file
var script2 = document.createElement('script');
script2.src = 'myscript.js'; // define the address of your javascript file.
script2.setAttribute("async", "");
document.body.append(script2);
resolve(false);
} else {
console.log("File exists");
resolve(true);
}
});
}
async function asyncCall(urlToFile) {
console.log('starting');
const result = await doesFileExist(urlToFile);
console.log(result);
console.log("finished");
}
asyncCall(urlToFile);
</script>
</body>
</html>
I think it is useful to mention that I changed your code from two "script" tags to only "one" and used "two" functions in it. one of them works on "xhr" request and adding script tags, and the other forces the code to wait until the xhr request is finished. I added "$("#top").fadeOut();" part of your code to a separate script code that is in the same directory and appended the script tag in first function.

Related

Why is this HTML code typed in URL bar as 'data:text/html' not working?

I have this html code (below), which works perfectly as a hosted file (meaning the code is working) -
<!DOCTYPE html>
<html>
<head>
<title>Read Text File</title>
<!--<script src="https://thunkable.github.io/webviewer-extension/thunkableWebviewerExtension.js" type="text/javascript"></script>-->
<script>
var ThunkableWebviewerExtension = (function () {
const postMessageToWebview = (message) => {
if (window.ReactNativeWebView) {
window.ReactNativeWebView.postMessage(message);
} else {
window.parent.postMessage(message, '*');
}
};
const getReceiveMessageCallback = (fxn, hasReturnValue) => (event) => {
if (typeof fxn === 'function') {
if (event.data) {
let dataObject;
try {
dataObject = JSON.parse(event.data);
} catch (e) {
// message is not valid json
}
if (dataObject && dataObject.type === 'ThunkablePostMessage' && hasReturnValue) {
fxn(dataObject.message, (returnValue) => {
const returnMessageObject = { type: 'ThunkablePostMessageReturnValue', uuid: dataObject.uuid, returnValue };
postMessageToWebview(JSON.stringify(returnMessageObject));
});
} else if (!hasReturnValue && (!dataObject || dataObject.type !== 'ThunkablePostMessage')) {
fxn(event.data);
}
}
}
};
return {
postMessage: postMessageToWebview,
receiveMessage: function(fxn) {
const callbackFunction = getReceiveMessageCallback(fxn, false);
document.addEventListener('message', callbackFunction, false);
window.addEventListener('message', callbackFunction, false);
},
receiveMessageWithReturnValue: function(fxn) {
const callbackFunction = getReceiveMessageCallback(fxn, true);
document.addEventListener('message', callbackFunction, false);
window.addEventListener('message', callbackFunction, false);
},
};
})();
</script>
</head>
<body>
<input type="file" name="inputfile" id="inputfile">
<br>
<pre id="output"></pre>
<script type="text/javascript">
document.getElementById('inputfile')
.addEventListener('change', function() {
var fr=new FileReader();
fr.onload=function(){
//document.getElementById('output').textContent=fr.result;
var msg = fr.result;
ThunkableWebviewerExtension.postMessage(msg);
}
fr.readAsText(this.files[0]);
})
</script>
</body>
</html>
What I want to do is, turn this whole code into a long URL, and I found that by using 'data:text/html,<meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>' at the start, then adding the code.
So the HTML url would become something like - 'data:text/html,<meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"/><!DOCTYPE html><html><head> ...'
I can see the file upload button, and even can select and upload a file. But, the script parts are not working - I am unable to catch the error here 😪
Kindly guide/advice me here... Thanks!
After experimenting a little bit, I think the problem might be that you haven't url-encoded it. Try using this instead of just pasting in the whole thing directly
(or copy it from here)
data:text/html,%3C!DOCTYPE%20html%3E%0A%3Chtml%3E%0A%3Chead%3E%0A%20%20%20%20%3Ctitle%3ERead%20Text%20File%3C/title%3E%0A%20%20%20%20%3C!--%3Cscript%20src=%22https://thunkable.github.io/webviewer-extension/thunkableWebviewerExtension.js%22%20type=%22text/javascript%22%3E%3C/script%3E--%3E%0A%20%20%20%20%3Cscript%3E%0A%20%20%20%20var%20ThunkableWebviewerExtension%20=%20(function%20()%20%7B%0A%20%20%20%20%20%20const%20postMessageToWebview%20=%20(message)%20=%3E%20%7B%0A%20%20%20%20%20%20%20%20if%20(window.ReactNativeWebView)%20%7B%0A%20%20%20%20%20%20%20%20%20%20window.ReactNativeWebView.postMessage(message);%0A%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20window.parent.postMessage(message,%20'*');%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D;%0A%20%20%20%20%0A%20%20%20%20%20%20const%20getReceiveMessageCallback%20=%20(fxn,%20hasReturnValue)%20=%3E%20(event)%20=%3E%20%7B%0A%20%20%20%20%20%20%20%20if%20(typeof%20fxn%20===%20'function')%20%7B%0A%20%20%20%20%20%20%20%20%20%20if%20(event.data)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20let%20dataObject;%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20dataObject%20=%20JSON.parse(event.data);%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20message%20is%20not%20valid%20json%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(dataObject%20&&%20dataObject.type%20===%20'ThunkablePostMessage'%20&&%20hasReturnValue)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20fxn(dataObject.message,%20(returnValue)%20=%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20returnMessageObject%20=%20%7B%20type:%20'ThunkablePostMessageReturnValue',%20uuid:%20dataObject.uuid,%20returnValue%20%7D;%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20postMessageToWebview(JSON.stringify(returnMessageObject));%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D);%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20if%20(!hasReturnValue%20&&%20(!dataObject%20%7C%7C%20dataObject.type%20!==%20'ThunkablePostMessage'))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20fxn(event.data);%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D;%0A%20%20%20%20%0A%20%20%20%20%20%20return%20%7B%0A%20%20%20%20%20%20%20%20postMessage:%20postMessageToWebview,%0A%20%20%20%20%20%20%20%20receiveMessage:%20function(fxn)%20%7B%0A%20%20%20%20%20%20%20%20%20%20const%20callbackFunction%20=%20getReceiveMessageCallback(fxn,%20false);%0A%20%20%20%20%20%20%20%20%20%20document.addEventListener('message',%20callbackFunction,%20false);%0A%20%20%20%20%20%20%20%20%20%20window.addEventListener('message',%20callbackFunction,%20false);%0A%20%20%20%20%20%20%20%20%7D,%0A%20%20%20%20%20%20%20%20receiveMessageWithReturnValue:%20function(fxn)%20%7B%0A%20%20%20%20%20%20%20%20%20%20const%20callbackFunction%20=%20getReceiveMessageCallback(fxn,%20true);%0A%20%20%20%20%20%20%20%20%20%20document.addEventListener('message',%20callbackFunction,%20false);%0A%20%20%20%20%20%20%20%20%20%20window.addEventListener('message',%20callbackFunction,%20false);%0A%20%20%20%20%20%20%20%20%7D,%0A%20%20%20%20%20%20%7D;%0A%20%20%20%20%7D)();%0A%20%20%20%20%3C/script%3E%0A%3C/head%3E%0A%0A%3Cbody%3E%0A%20%20%20%20%3Cinput%20type=%22file%22%20name=%22inputfile%22%20id=%22inputfile%22%3E%0A%20%20%20%20%3Cbr%3E%0A%0A%20%20%20%20%3Cpre%20id=%22output%22%3E%3C/pre%3E%0A%20%20%20%20%0A%20%20%20%20%3Cscript%20type=%22text/javascript%22%3E%0A%20%20%20%20%20%20%20%20document.getElementById('inputfile')%0A%20%20%20%20%20%20%20%20%20%20%20%20.addEventListener('change',%20function()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20fr=new%20FileReader();%0A%20%20%20%20%20%20%20%20%20%20%20%20fr.onload=function()%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20//document.getElementById('output').textContent=fr.result;%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20msg%20=%20fr.result;%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ThunkableWebviewerExtension.postMessage(msg);%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20fr.readAsText(this.files%5B0%5D);%0A%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%3C/script%3E%0A%3C/body%3E%0A%3C/html%3E%0A
But I could be wrong -- I'm not very experienced with javascript

I can't link javascript files as commonjs modules

I have:
test.json - contains the content to be uploaded into the HTML page
test.js - contains the function that sends an Ajax request to the JSON file, parses, compiles with Handelbars Temlate and puts the content into the HTML page (using innerHTTML).
addcontent.js - javascript file which calls the function from the test.js file
index.html - contains the Handlebars Template, Div
where the content will be placed after processing, and a link to the
addcontent.js.
Everything works, if inside index.html there is a link directly to test.js.
Everything works if I wrap the code inside test.js in a function with variables and call this function in the same file.
But if I call this function from addcontent.js and connecting addcontent.js and test.js using commonJS module approach, it does not work.
Probably I made a syntax mistake somewhere, but I don't see it.
P.S. I use NodeJS, NPM, HTTP-server and I'm going to merge all javascript files using browserify after all
//test.js
module.exports = function addContent (jsonDir, templId, finId){
function sendGet(callback) {
/* create an AJAX request using XMLHttpRequest*/
var xhr = new XMLHttpRequest();
/*reference json url taken from: http://www.jsontest.com/*/
/* Specify the type of request by using XMLHttpRequest "open",
here 'GET'(argument one) refers to request type
"http://date.jsontest.com/" (argument two) refers to JSON file location*/
xhr.open('GET', jsonDir);
/*Using onload event handler you can check status of your request*/
xhr.onload = function () {
if (xhr.status === 200) {
callback(JSON.parse(xhr.responseText));
} else {
alert(xhr.statusText);
}
};
/*Using onerror event handler you can check error state, if your request failed to get the data*/
xhr.onerror = function () {
alert("Network Error");
};
/*send the request to server*/
xhr.send();
}
//For template-1
var dateTemplate = document.getElementById(templId).innerHTML;
var template = Handlebars.compile(dateTemplate);
sendGet(function (response) {
document.getElementById(finId).innerHTML += template(response);
})
}
/* test.json */
{
"time": "03:47:36 PM",
"milliseconds_since_epoch": 1471794456318,
"date": "08-21-2016-123",
"test": "lalala 123"
}
/* addcontent.js */
var addContent = require('./test');
addContent("json/test.json", "date-template", 'testData');
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="handlebars-v4.0.5(2).js"></script>
</head>
<body>
<!-- template-1 -->
<div id="testData"></div>
<script id="date-template" type="text/x-handlebars-template">
Date:<span> <b>{{date}}</b> </span> <br/> Time: <span><b>{{time}}</b>
</span>
</script>
<script type="text/javascript" src="addcontext.js"></script>
</body>
</html>

Loading js dynamically not reflecting

I want to load js on the fly which is happening but the one more js file which is included in index is loading before (file i am loading dynamically) is there way to fix the order
i am adding global.js dynamically and i want variable declared in global.js shoud be initialised before dynamicjs.DynamicJs is loaded
------------- Index.html -------------
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<script src="resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-libs="sap.ui.commons"
data-sap-ui-theme="sap_goldreflection" >
</script>
<!-- add sap.ui.table,sap.ui.ux3 and/or other libraries to 'data-sap-ui-libs' if required -->
<script src="js/dyn.js"></script>
<script></script>
<script>
sap.ui.localResources("dynamicjs");
var view = sap.ui.view({id:"idDynamicJs1", viewName:"dynamicjs.DynamicJs", type:sap.ui.core.mvc.ViewType.JS});
view.placeAt("content");
</script>
</head>
<body class="sapUiBody" role="application">
<div id="content"></div>
</body>
</html>
function loadScript(url){
var xhrObj = createXMLHTTPObject();
// open and send a synchronous request
xhrObj.open('GET', url, false);
xhrObj.send('');
var e = document.getElementsByTagName("script")[1];
var d = document.createElement('script');
d.src = url;
d.type = 'text/javascript';
d.async = false;
d.defer = false;
e.parentNode.insertBefore(d,e);
}
function addScriptDynamically(){
loadScript('js/global.js'+'?scheme=12345');
}
function createXMLHTTPObject(){
var xmlhttp=new XMLHttpRequest();
if( typeof xmlhttp == 'undefined' || xmlhttp == null )
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
return xmlhttp;
}
/*call function */
addScriptDynamically();
Why won't you try to load script with jQuery.getScript()
http://api.jquery.com/jQuery.getScript/
If you want compatibility with other libraries like prototype or mootools you can set jQuery.noConflict()

Get the status of an object on eventhandling in JavaScript

My source code :
<!doctype html>
<html>
<head>
<title>onload test</title>
<link type="text/css" rel="stylesheet" href="spot.css" media="screen" />
</head>
<body>
<h1>Welcome Page</h1>
<script>
debugger;
function constructScripts(url, callBack) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
if (script.readyState) {
script.onreadystatechange = function () {
if (script.readyState == "loaded" || script.readyState == "complete") {
script.onreadystatechange = null; callBack();
}
};
}
else {
script.onload = callBack;
}
}
</script>
<script>
debugger;
myCallBack = function () {
alert(this.src + "loaded");
}
constructScripts("files1", myCallBack);
constructScripts("files2", myCallBack);
constructScripts("files3", myCallBack);
</script>
</body>
</html>
this.src is undefined here. I guess this should be an 'script' object which supposed to have its src property so that I can read the filename. Who is this here? And also when I view the page source these scripts were not included in the header() section. Why is it so?
this.src is undefined here.
It shouldn't be… It is defined earlier: script.src = url
I guess this should be an 'script' object which supposed to have its src property so that i can read the filename. Who is 'this' here?
The script element upon which the onload or readystatechange event fires
And also when i view the page source these scripts were not included in the header() section. Why is it so?
Because you are looking at the page source, not a serialisation of the live DOM after it has been manipulated by JavaScript.
When you call you callBack function, pass it the script object like callBack(script). Modify the callBack function like
myCallBack = function (script) {
alert(script.src + "loaded");
}
View source does not show dinamically loaded elements.
You need to extend your function using prototype.
Element.prototype.MyMethod = function(){}
Look at your edited code
<!doctype html>
<html>
<head>
<title>onload test</title>
<link type="text/css" rel="stylesheet" href="spot.css" media="screen" />
</head>
<body>
<h1>Welcome Page</h1>
<script>
Element.prototype.MyMethod = function(){}
function constructScripts(url, callBack) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
script.MyMethod = callBack;
document.getElementsByTagName("head")[0].appendChild(script);
if (script.readyState) {
script.onreadystatechange = function () {
if (script.readyState == "loaded" || script.readyState == "complete") {
script.onreadystatechange = null;
script.MyMethod();
}
};
}
else {
script.onload = callBack;
}
}
</script>
<script>
myCallBack = function () {
alert(this.src + "loaded");
}
constructScripts("files1", myCallBack);
constructScripts("files2", myCallBack);
constructScripts("files3", myCallBack);
</script>
</body>
</html>

javascript connect to web site code not working

Here is my javascript code which ping Google for every 10 seconds and display the connection status to html MonitorInformation element. But when I click the html file to debug, the information displayed at MonitorInformation element is always "Connecting...wait". I have debugged for some time but can not figure out. Any ideas what is wrong with my code?
Html code:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="Monitor.js" type="text/javascript"></script>
<title>Web Site Monitor</title>
</head>
<body onload="setup()">
<div id="MonitorInformation">Connecting...wait</div>
</body>
</html>
Java script code:
function setup() {
window.setInterval(PingWebSite, (10 * 1000));
}
function PingWebSite() {
conObj = new ActiveXObject("Msxml2.XMLHTTP");
conObj.open("GET", "http://www.google.com", true);
conObj.onreadystatechange = function() {
if (conObj.readyState === 4) {
if (conObj.status === 200) {
loading.innerText = "Service is available";
} else {
MonitorInformation.innerText = "Service is not available";
}
} else {
MonitorInformation.innerText = "Connecting to www.google.com ...";
}
}
}
EDIT 1: my fix using JSON
function setup() {
window.setInterval(PingWebSite, (10 * 1000));
}
function PingWebSite() {
var http_request = new XMLHttpRequest();
http_request.open("GET", "http://www.google.com", true);
http_request.send(null);
http_request.onreadystatechange = function() {
if (http_request.readyState == 4) {
if (http_request.status == 200) {
MonitorInformation.innerText = "Connection ok";
alert("ok");
} else {
MonitorInformation.innerText = "Connection fail";
alert("fail");
}
http_request = null;
}
};
}
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="Monitor.js" type="text/javascript"></script>
<title>Web Site Monitor</title>
</head>
<body onload="setup()">
<div id="MonitorInformation">Connecting...wait</div>
</body>
</html>
thanks in advance,
George
You can't connect to a site outside of your URL. Unless your code is on the google.com domain it won't work.
This is a browser security item called 'Same origin policy' http://en.wikipedia.org/wiki/Same_origin_policy
If you want to do cross site calls like that you will have to use JSONP http://en.wikipedia.org/wiki/JSON as that lets you do that.
You can't cross domain XHR for which you don't have access to AFAIK.
You can do this using a hidden iFrame to get around the cross domain limitations. A quick example to get you started:
(HTML Snippet)
<body>
<div style="display: none;">
<iframe id='hiddenFrame'></iframe>
</div>
</body>
Javascript:
function setup()
{
var iFrame = document.getElementById('hiddenFrame');
var changeEvent = function ()
{
loading.innerText = "Service is Available";
}
// IE
iFrame.onload = changeEvent;
// Firefox
iFrame.onreadystatechange = changeEvent;
setInterval(PingWebSite, (10 * 1000));
}
function PingWebSite() {
var iFrame = document.getElementById('hiddenFrame');
iFrame.src = 'http://www.google.com';
}
Could it be that you forgot a semicolon there? E.g.: ...body onload="setup();"...

Categories