'$ is not defined' on first load - javascript

I'm writing a html plugin for a tool(sonarqube).
In this I need to write code in below fashion by first registering a extension.
While running the code, I'm facing:
ReferenceError: $ is not defined
Code:
window.registerExtension('CustomPlugin/muPlugin', function (options) {
script = document.createElement('script');
script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js';
document.head.appendChild(script);
var pluginContainer = document.createElement('div');
pluginContainer.setAttribute("id", "pluginContainer");
options.el.appendChild(pluginContainer)
$("#pluginContainer").load("/static/CustomPlugin/customPluginWebPage.html"); // Facing error on this line.
return function () {};
});
It works when I load the plugin second time, but not the first time.
Any suggestion, how can I make sure jquery is available the first time?
Thanks you

Possible duplication of - document.createElement(“script”) synchronously
ES5:
You can create your element with an "onload" handler, and that will be called when the script has been loaded and evaluated by the browser.
script = document.createElement('script');
script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js';
//Bind a onload handler
script.onload = () => {
console.log($);
};
document.head.appendChild(script);
EDIT 1:
ES6:
The above is the best solution, unless you're prepared to host jQuery locally then you could use dynamic import() which runs asynchronously. Support is not great - https://caniuse.com/#feat=es6-module-dynamic-import. Here is another link making use of this. I would only recommend using this where BabelJS is used.
import('./jquery.min.js').then((jquery) => {
window.jQuery = jquery;
window.$ = jquery;
// The rest of your code
});

Try using setTimeOut()
window.registerExtension('CustomPlugin/muPlugin', function (options) {
script = document.createElement('script');
script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js';
document.head.appendChild(script);
var pluginContainer = document.createElement('div');
pluginContainer.setAttribute("id", "pluginContainer");
options.el.appendChild(pluginContainer);
setTimeout(() => {
$("#pluginContainer").load("/static/CustomPlugin/customPluginWebPage.html");
}, 2000);
return function () {};
});

Related

Callback in JavaScript

I'm studying about callbacks and other stuff like this, and in this
book(https://javascript.info/callbacks) there was example with this code
function loadScript(src, callback) {
let script = document.createElement('script');
script.src = src;
script.onload = () => callback(script);
document.head.append(script);
}
loadScript('https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js', script => {
alert(`Cool, the script ${script.src} is loaded`);
alert( _ ); // function declared in the loaded script
});
It appends to the document the new, dynamically created, tag <script src="…"> with given src.
The browser automatically starts loading it and executes when complete. I have a question:
Do I understand it right, that it should work with any kind of links, and get(obtain) functions and their results on that links?
And in this example the second alert should show some sort of result of that functions?
If so, how to insert in src another link with code? I've tried many other links, but second alert didn't work. For example:
function loadScript(src, callback) {
let script = document.createElement('script');
script.src = src;
script.onload = () => callback(script);
document.head.append(script);
}
loadScript('https://jsfiddle.net/Rom28/7rL28mso/', script => {
alert(`Cool, the script ${script.src} is loaded`);
alert(test()); // function declared in the loaded script
});
Please clarify it to me.
Also I want to ask what does null mean in this code:
function loadScript(src, callback) {
let script = document.createElement('script');
script.src = src;
script.onload = () => callback(**null**, script);
script.onerror = () => callback(new Error(`Script load error for ${src}`));
document.head.append(script);
}
It's the same code as above but it also has functionality for handling errors.
src parameter should contain link to js file (jsfiddle link doesn't contain js code only so it won't work). For instance you can try to create script.js file with test function in it and put loadScript function in your html file:
function loadScript(src, callback) {
let script = document.createElement('script');
script.src = src;
script.onload = () => callback(script);
document.head.append(script);
}
loadScript('script.js', script => {
alert(`Cool, the script ${script.src} is loaded`);
alert(test()); // function declared in the loaded script
});
So now you have access to the test function which is written in script.js

How do I load the functions of a JavaScript File called through a JavaScript Object

I have a local JS file that needs to be called using a script object. However, I am not able to get the functions to run. Here's the code snippet.
<script type="text/javascript">
var x = document.createElement("SCRIPT");
x.type = "text/javascript";
x.src = "file:///C:/scripts/localscript.js";
//one of the functions is loadData();
loadData(); //I'm getting reference error, loadData is not defined.
</script>
Thank you,
You need to create a script element and insert it in DOM (mostly under head) to load the script. When that script is loaded by the browser, whatever you return from that script will be available.
Consider sampleScript.js with below code
(function(window){
'use strict';
window.app = {
sayHi: function() {
console.log('Hey there !');
}
};
})(this);
To load this script, I do
<script>
var node = document.createElement('script');
node.src = 'sampleScript.js';
node.addEventListener('load', onScriptLoad, false);
node.async = true;
document.head.appendChild(node);
function onScriptLoad(evt) {
console.log('Script loaded.');
console.log('app.sayHi ---> ');
app && app.sayHi();
}
</script>
Taking cues, you can fit to your need. Hope this helps.
Use the onload event:
x.onload = function() { window.loadData(); }

$.Event is not a function error

I am creating an simple Javascript BOT.Its an simple js bookmarklet when clicked will create blogs in Blogger.com...I used Below code
var script = document.createElement('script');
script.src = 'http://jqueryjs.googlecode.com/files/jquery-1.2.6.min.js';
script.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(script);
document.getElementsByClassName('blogg-button GEE3RVNDMU')[0].click()
document.getElementById("newBlog-title").value ="hello blogger";
var node = document.getElementById("newBlog-address");
node.focus();
document.getElementById("newBlog-address").value ="hellosblogger";
setTimeout(function() {game();},1250);
function game()
{
var e = $.Event("keydown", { keyCode: 8});
$("body").trigger(e);
}
Everything works perfect,But atlast I need to simulate Any keypress Event...So i used that in function game , But I get $.Event is not a function error in Firexfox console . Please some one guide me or please tell any alternative to do an simple keypress event..It can be any key.
There really is no function named Event in the jquery library. To bind a event to jquery object, you can use Jquery.Bind which actually has the same syntax as the one you've used in your code.
So, to summarize:
$.bind("keydown",function(){})
For more info: http://api.jquery.com/bind/
See this link.
All works without errors.
Maybe you should use latest version of jQuery.
Code:
var script = document.createElement('script');
script.src = 'http://code.jquery.com/jquery-1.10.2.min.js';
script.type = 'text/javascript';
script.onload = game;
document.body.appendChild(script);
function game() {
console.log($("body"));
var e = $.Event("keydown", { keyCode: 8});
$("body").trigger(e);
}

Delay script loading

So if I have the following:
<script type="text/javascript" src="offsite file I am referencing"></script>
and I simply want to delay the execution of calling that file using settimeout, how would I go about that?
Very strange in that I would have no problem using settimeout on a simple function, but I am kind of stumped in this seemingly more simple situation.
My thought would be I could just make a function that calls that file after x amount of time, but calling the file in the function seems to be escaping me.
you are almost there.
in your settimeout callback function do the following:
var script = document.createElement('script');
script.src = "http://whatever.com/the/script.js";
document.getElementsByTagName('head')[0].appendChild(script);
The simplest way would be to let the script file load normally and just call a main function in it with setTimeout() like this:
<script type="text/javascript" src="offsite file I am referencing"></script>
<script type="text/javascript">
setTimeout(executeMainFunction, 5000); // function in offsite js file
</script>
If you cannot do that for some reason, then you can delay the loading of the external script file like this:
setTimeout(function() {
var headID = document.getElementsByTagName("head")[0];
var newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.src = 'http://www.somedomain.com/somescript.js';
headID.appendChild(newScript);
}, 5000);
Here's a reference article on dynamic loading of script files (and other types of resources): http://www.hunlock.com/blogs/Howto_Dynamically_Insert_Javascript_And_CSS.
You can use DOM manipulation to create a new script tag at runtime. Adding it into the document will load the external JS file just as if you had written it into the HTML in the first place.
var loadScript = function(sourceSrc){
var scriptTag = document.createElement('script');
scriptTag.src = scriptSrc;
document.getElementsByTagName('head')[0].appendChild(scriptTag);
}
You can delay the script from loading, until the page finishes loading, using the HTML script defer attribute:
<script src="offsite file I am referencing" defer></script>
If the purpose of this exercise is to delay the loading of external resources to simulate potential real life scenarios (e.g. when loading 3rd party widgets, etc), then I'd go down a very different route.
The following are two different delay proxy implementations that can be used to simulate and test unexpected network conditions:
http://www.deelay.me/
https://www.npmjs.com/package/grunt-connect-delay
They both work by using a prefix like /delay/5000/ to specify the delay simulation period.
Mozilla Developer Network explains various approaches:
MDN Async Script Techniques
<script async src="file.js"></script>
or
var script = document.createElement('script');
script.src = "file.js";
document.body.appendChild(script);
or if your JavaScript is in a String:
var blob = new Blob([codeString]);
var script = document.createElement('script');
var url = URL.createObjectURL(blob);
script.onload = script.onerror = function() { URL.revokeObjectURL(url); };
script.src = url;
document.body.appendChild(script);
There is also good information when async is not async as well as how to get around those cases.
I have created for ReactJS and its worked for me.
1. File: widget.js with promise:
const delayTime = 20000; // loading 20sec delay.
const loadJS = async () => {
return await new Promise(function (resolve, reject) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.src = 'https://yoururl.com/js/widget.js';
script.onload = resolve;
script.onerror = () => {
reject('Cannot load js')
document.head.removeChild(script);
}
document.head.appendChild(script);
}) }
function initLoadJS() {
loadJS()
.then(()=> console.log('testing'))
.catch((error)=>console.error(error)) }
function delayLoadingJS() {
setTimeout((event)=>initLoadJS(event), delayTime);
}
export default delayLoadingJS;
2. Calling delayLoadingJS() function on the page:
When page loading completed then after 20 sec later initLoadJS() method will trigger and it attach the 3rd party javascript file(https://yoururl.com/js/widget.js) on page.
componentDidUpdate(prevProps, prevState) {
if (this.state.page !== prevState.page) {
delayLoadingJS();
}
}
For a NextJS cript, the code below will work fine:
<script id="sample_id">
setTimeout(function(){
var script = document.createElement('script');
script.src = "https://link_to_load";
document.getElementsByTagName('head')[0].appendChild(script);
},
4000);
</script>

Inject a script tag with remote src and wait for it to execute

How can I inject a <script src="https://remote.com/"></script> element into my page, wait for it to execute, and then use functions that it defines?
FYI: In my case, the script will do some credit card processing in rare cases, so I don't want to include it always. I want to include it quickly when the user opens up a change-credit-card-options dialog, and then send it the new credit card options.
Edit for additional detail: I do not have access to the remote script.
You could use Google Analytics or Facebook's method:
(function(d, script) {
script = d.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.onload = function(){
// remote script has loaded
};
script.src = 'http://www.google-analytics.com/ga.js';
d.getElementsByTagName('head')[0].appendChild(script);
}(document));
UPDATE:
Below is the new Facebook method; it relies on an existing script tag instead of <head>:
(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)){ return; }
js = d.createElement(s); js.id = id;
js.onload = function(){
// remote script has loaded
};
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
Replace facebook-jssdk with your unique script identifier to avoid it being appended more than once.
Replace the script's url with your own.
Same method using event listeners and ES2015 constructs:
function injectScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.addEventListener('load', resolve);
script.addEventListener('error', e => reject(e.error));
document.head.appendChild(script);
});
}
injectScript('https://example.com/script.js')
.then(() => {
console.log('Script loaded!');
}).catch(error => {
console.error(error);
});
This is one way to dynamically load and execute a list of scripts synchronously. You need to insert each script tag into the DOM, explicitly setting its async attribute to false:
script.async = false;
Scripts that have been injected into the DOM are executed asynchronously by default, so you have to set the async attribute to false manually to work around this.
Example
<script>
(function() {
var scriptNames = [
"https://code.jquery.com/jquery.min.js",
"example.js"
];
for (var i = 0; i < scriptNames.length; i++) {
var script = document.createElement('script');
script.src = scriptNames[i];
script.async = false; // This is required for synchronous execution
document.head.appendChild(script);
}
// jquery.min.js and example.js will be run in order and synchronously
})();
</script>
<!-- Gotcha: these two script tags may still be run before `jquery.min.js`
and `example.js` -->
<script src="example2.js"></script>
<script>/* ... */<script>
References
There is a great article by Jake Archibald of Google about this called Deep dive into the murky waters of script loading.
The WHATWG spec on the tag is a good and thorough description of how tags are loaded.
Dynamic import()
Using dynamic import, you can now load modules and wait for them to excute, as simply as this:
import("http://example.com/module.js").then(function(module) {
alert("module ready");
});
If the module has already been loaded and executed, it won't get loaded and executed again, but the promise returned by import will still resolve.
Note that the file is loaded as a module, not as just a script. Modules are executed in strict mode, and they are loaded in module scope, which means variables are not automatically made global the way they are in normally loaded scripts. Use the export keyword in a module to share a variable with other modules or scripts.
References:
Browser support for dynamic import
ES modules: A cartoon deep-dive
Dynamic import()
something like this should do the trick:
(function() {
// Create a new script node
var script = document.createElement("script");
script.type = "text/javascript";
script.onload = function() {
// Cleanup onload handler
script.onload = null;
// do stuff with the loaded script!
}
// Add the script to the DOM
(document.getElementsByTagName( "head" )[ 0 ]).appendChild( script );
// Set the `src` to begin transport
script.src = "https://remote.com/";
})();
hope that helps! cheers.
Create a loader
You can inject the script in an orderly manner in a loader.
Beware that the execution of the dynamically loaded scripts usually comes after statically loaded scripts (i.e.<script src="My_script.js"></script>) (the order of injection in the DOM does not guarantee the opposite):
e.g., loader.js:
function appendScript(url){
let script = document.createElement("script");
script.src = url;
script.async = false //IMPORTANT
/*Node Insertion Point*/.appendChild(script);
}
appendScript("my_script1.js");
appendScript("my_script2.js");
my_script1.js will effectively be executed before my_script2.js, (helpful if dependencies of my_script2.js are in my_script1.js)
Note it's important to have script.async = false because dynamically loaded scripts has async = true by default, async does not assure you the order of loading.
Here is my adapted version, based on the answer of Frank:
static async importScript(src, expressionToEvaluateAndReturn){
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.async = true;
script.src = src;
script.addEventListener('load', (event)=>{
if(expressionToEvaluateAndReturn){
try{
let result = eval(expressionToEvaluateAndReturn);
resolve(result);
} catch(error){
reject(error);
}
} else {
resolve();
}
});
script.addEventListener('error', () => reject('Error loading script "' + src + '"'));
script.addEventListener('abort', () => reject('Script loading aborted for "' + src + '"'));
document.head.appendChild(script);
});
}
Example usage:
let d3 = await importScript('/bower_components/d3/d3.min.js','d3')
.catch(error => {
console.log(error);
throw error;
});

Categories

Resources