I offen heard that loading jquery as last element is a good idea because this way a web page loads faster. At the same time I have a script in the header which shows error:
$(document).ready(function () {// Uncaught ReferenceError: $ is not defined
...
}
Should I move jquery loader before the script or I need to change this script some way?
Your concrete issue stems from the fact that you execute statements that use jQuery (i.e. they execute $, which is a function in the jQuery library, also called "the jQuery function" because jQuery is an alias) before it is loaded.
True, it is typically recommended to load scripts last, but that still means the scripts have to be loaded in the correct order, with usually jQuery before your own scripts using jQuery.
If you really want to load your own scripts before jQuery for some reason, you need to defer its execution and have a third helper script to run it, e.g.:
// script.js
(function() {
function myLibraryMainFn() {
$('div').text('simulating work, utilizing jQuery');
}
window.myNamespace = {
run: function() {
myLibraryMainFn()
}
};
}());
<!DOCTYPE html>
<html>
<body>
<div></div>
<script src="script.js"></script>
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script>
// Run your script now:
window.myNamespace.run();
</script>
</body>
</html>
Always refer library file first(in your case jQuery), then use it next..For page load and performance add it before body end tags of your HTML
Related
I'm trying to create a theme app extension for shopify to run some javascript when the add to cart button is clicked. As an example:
<head>
<script type="text/javascript" src={{ 'jquery-3.6.0.js' | asset_url }} defer></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" rel="preload" defer="defer"></script>
</head>
...
<button id="add-btn">click me!</button>
<script>
jQuery( document ).ready(function() {
$('#add-btn').on('click', function(event){
alert("clicked")
})
});
</script>
This is within a sheet app extension in the blocks folder.
It seems like jquery isn't loading, and I get an error
Uncaught ReferenceError: jQuery is not defined
Any ideas why?
Summary: You are loading the jQuery library using the defer keyword so that it doesn't block the page load, but are referencing jQuery before the page finishes loading.
By loading jQuery using the defer attribute on the script tag, the browser will start loading the script immediately but won't execute the script until the DOM content has loaded:
<script type="text/javascript" src={{ 'jquery-3.6.0.js' | asset_url }} defer></script>
However, the inline script tag further down the page will be run immediately when the browser gets to it:
<script>
jQuery( document ).ready(function() { // ERROR! jQuery library hasn't been run yet, so we can't use jQuery to select the document!
$('#add-btn').on('click', function(event){
alert("clicked")
})
});
</script>
Since deferred scripts are executed in the order that they are defined, your instinct might be to try putting the defer keyword on the inline script tag - but unfortunately, defer and async only apply to external script files.
There are several ways that we could resolve this timing issue. Two possibilities are:
1: Move the inline script to an external Javascript file
If you create an external JS file, you can load the script using the defer keyword as all deferred scripts execute in the order that they were called once the DOM is ready. As an added bonus, you wouldn't need to wrap your function with the jQuery(document).ready as you would already know that the document is ready when the script executes.
2: Use vanilla Javascript rather than jQuery to set up your event listener
If the inline script tag makes sense, then using vanilla Javascript to set up your event will solve your issue. The equivalent code would be to use the addEventListener function to listen for the DOMContentLoaded event:
<script>
// This event is created before the DOM is loaded, so jQuery doesn't exist yet
document.addEventListener('DOMContentLoaded', function() {
// This event will be run after the deferred scripts above, so jQuery exists now
$('#add-btn').on('click', function(event){
alert("clicked")
})
});
</script>
I the defer attribute of the script tag in the <head> section of HTML files. This almost always means that I cannot run js functions in the HTML since the js file is only loaded after the HTML file has been loaded..
I have run into a situation where I needed to run a js function in my HTML file, but would not want to remove the defer attribute from the script tag because of other functions in the js file. I looked at the possibility of using async, but it also was not helpful.
Any idea on how this could be done... other than using defer? I would still like to keep the script tag in the head, but going that way would mean that I have no open (non-function based) instructions in the linked js file... which is not always ideal.
Here is a sample of the HTML file
temp.html
<!DOCTYPE html>
<html lang="en">
<head>
<script src="temp.js" defer></script>
<title>Defer et al</title>
</head>
<body>
<script>
runThisFunction('Home');
</script>
</body>
</html>
And here is a sample of the js file
temp.js
function runThisFunction(varin) {
console.log(varin);
}
If I remove the defer from the js file, the function will run; if I leave it there, or use async instead, the function will not run because it has not loaded yet.
Any assistance in this small issue will be appreciated.
The best way to do this would be to refactor your script to contain an entry point in a function, and run that function once the DOM loads. Instead of, for example
// temp.js
function runThisFunction(varin) {
console.log(varin);
}
document.querySelector('.foo').textContent = 'doing stuff';
// other code here
put all of the functionality that depends on the page being loaded into its own function:
// temp.js
function runThisFunction(varin) {
console.log(varin);
}
function init() {
document.querySelector('.foo').textContent = 'doing stuff';
// other code here
}
window.addEventListener('DOMContentLoaded', init);
This way, if you also remove the defer attribute, runThisFunction will be available immediately, but the other parts of your code won't run until the page is loaded.
::SOLVED::
I have an index.php and I define some JavaScript function for do some thing in this page. I use jQuery in this functions. When I put the functions in the index.php between tags all thing work good but I need to put this functions in external is file. When I do it and then import it in index.php, the js file load and the part that don't use jQuery, work good but the jQuery actions not work! I have put the jQuery before is in head of index.php. the jQuery load and I test it by simple alert. I tried to put $(function).ready() surrounding the js function and other time surrounding the function content but it doesn't work!
<script language='javascript' src="/js/jquery-3.4.1.js"></script>
<script type="text/javascript" language='javascript' src="/js/external.js"></script>
And external js file like this:
function doSomething(){
//some JavaScript code that work good
//some jQuery code that doesn't work!
}
Where is wrong?!
Excuse me for my stupid question!
First of all write better HTML code.
<script src="/js/jquery-3.4.1.js"></script>
<script src="/js/external.js"></script>
function doSomething(){
console.log("I'm executed");
if (typeof jQuery !== 'undefined') {
console.log(jQuery.fn.jquery);
} else {
console.log("jQuery library not loaded check your Network tab");
}
}
Then seems your jQuery not loaded check your network tab for loaded scripts.
I am using Bootstrap as my template, and Laravel as my framework. As suggested within the examples, you should load your jQuery script at the bottom of the page - to speed up the loading.
Within my application, I have this function that checks if an alert exists in the session, and if so, show it:
$(document).ready(function() {
toastr.options = {
"closeButton": false
};
toastr. {
{
Session::get('flash_notification.level')
}
}('{{ Session::get('
flash_notification.message ') }}')
});
This is shown above where I load the jQuery script:
#if (Session::has('flash_notification.message'))
<script>
The above script is loaded here.
</script>
#endif
#yield('content')
</div>
<!-- Scripts -->
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
In order to get this working, I need to declare my jQuery file in the header of the template, but I know this isn't best practice. I initially thought that by using the $(document).ready() method, it would resolve this, but it doesn't.
Any help would be greatly appreciated.
It is best to put the script calls in the footer so they are loaded last. This means that any other JS you write will need to be below them. You could add your other JS to another file which is included after the jQuery load.
If you cannot, you could add it to the header and add the defer attribute to the script tag to defer it's loading.
Option 1 should be preferred though.
I'm working on a plugin that allows to inject 3rd party code into a page (either as iframe or directly into the DOM).
My problem is "direct injections", because I need to make sure, I don't add any <scripts> additional times, if they are needed in my main page and in a page I'm loading and injecting.
For example (and I can't use requireJS), my page.html looks like this:
<html>
<head>
<script type="text/js" src="jquery.js"></script> // exports window.$
<script type="text/js" src="foo.js"></script> // exports window.foo
</head>
<body>
<!-- things that make foo load anotherPage.html and append its content here -->
</body>
</html>
with anotherPage.html
<html>
<head>
<script type="text/js" src="foo.js"></script> // exports window.foo
</head>
<body>
<!-- stuff that also runs on FOO -->
</body>
</html>
Page loading is done via Ajax and when I'm processing the data returned by my request for anotherPage.html I end up with a list of all elements after doing this:
cleanedString = ajaxResponseData
.replace(priv.removeJSComments, "")
.replace(priv.removeHTMLComments,"")
.replace(priv.removeLineBreaks, "")
.replace(priv.removeWhiteSpace, " ")
.replace(priv.removeWhiteSpaceBetweenElements, "><");
// this will return a list with head and body elements
// e.g. [meta, title, link, p, div, script.foo]
content = $.parseHTML(cleanedString, true);
// insert into DOM
someTarget.append(content);
This is where I'm stuck trying to detect whether a script I'm about to append to the document is already there.
I cannot go by the src, because the filename may differ and a script may be hosted on a different domain (with Access-Control-Allow-Origin correctly set). I also don't know, what and if the script I'm about to append returns a global I already have defined and I can't/don't want to use eval() to find out.
Question:
Is there any way to identify whether a plugin or script that may return a global is already "on" a page, when I only have the "non-appended" <script> element available?
Thanks!
here is an example of my self-enclosed module pattern, i call it a "Sentinel":
(function wait(){
if(!self.$){
if(!wait.waitingJQ){
wait.waitingJQ=true;
addScriptTag(JQUERY_URL);
}
return setTimeout(wait, 44);
}
doStuffThatNeedsJquery();
}());
The sentinel pattern work from anywhere (internal or external), doesn't care about script loading order, and works with ANY script loading library. you can list additional depends below the jQuery fork in the same manner, just put your greedy code at the bottom of the sentinel wrapper function.