Shopify app theme extensions jQuery not loading/not working - javascript

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>

Related

HTML - Adding the script in the head or in the body (to translate the DOM)?

I am doing the following to translate my html page:
<head>
<script type="module" src="js/scripts/home.js"></script>
</head>
<body>
<h1 id="hello">Hello world!</h1>
</body>
and
import $ from "jquery";
import { t } from "../lib/i18n";
function main() {
$("#hello").text(t("hello"));
}
main();
I do not understand why this work, I thought that, in order to manipulate the DOM, we should wait to get it ready...
By the other hand, if I add the script at the end of the body tag, the look-and-feel is worse, because there is a little timeout before the translation.
<body>
<h1 id="hello">Hello world!</h1>
<script type="module" src="js/scripts/home.js"></script>
</body>
Another option, with the same behavior, is to include the script at the head but change the js code to:
import $ from "jquery";
import { t } from "../lib/i18n";
function main() {
$("#hello").text(t("hello"));
}
$(main); // on DOM ready <---------
What is the suggested way to go here and why?
See the MDN documentation for script elements:
defer
This Boolean attribute is set to indicate to a browser that the script
is meant to be executed after the document has been parsed, but before
firing DOMContentLoaded.
Scripts with the defer attribute will prevent the DOMContentLoaded
event from firing until the script has loaded and finished evaluating.
Warning: This attribute must not be used if the src attribute is
absent (i.e. for inline scripts), in this case it would have no
effect.
The defer attribute has no effect on module scripts — they defer by
default.
Since it is a module, it is automatically deferred, so won't run until the DOM is ready, thus you don't need to write any JS to explicitly wait for the DOM to be ready.
you can use defer in script attribute.
or write the script tag under the body tag, In the html tag.

jQuery window on load is firing too early. What else can I use? Javascript in Wordpress

I'm learning jQuery and Javascript, and I'm trying to understand why my code is not working.
I'm doing this from inside a custom plugin in WordPress.
My javascript file with the function I'm trying to call is enqueued in the WordPress footer:
<script type='text/javascript' src='..... gf_timer.js?ver=1.1.0.1'></script>
and my PHP is generating items like the following:
<div id="gf_timer_1">Placeholder</div>
<script type="text/javascript">$j=jQuery.noConflict(); $j(window).on('load',gfInitTimer(1));</script>
I just want to call the function gfInitTimer() after each div. I keep on getting an error "gfInitTimer is not defined".
So I added the onclick handler as a test and that's finding the function properly:
<div id="gf_timer_1" onclick="gfInitTimer(1)">Placeholder</div>
<script type="text/javascript">$j=jQuery.noConflict(); $j(window).on('load',gfInitTimer(1));</script>
I thought the window.on('load', should fire after the page and all scripts are loaded.
What am I missing?
if you want to load gfInitTimer right after the page is loaded try using ready as shown:
$(document).ready(function(){
//run your gfInitTimer here
});

Loading jquery in the last position

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

jQuery script only working if it's above a function

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.

Jquery - Linking external .js file not working

For some reason the external .js file I am linking to isn't working. I am linking to it like so:
<script src="jquery.js" type="text/javascript"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
I have tested jquery using a simple inline script to hide a paragraph of text when it is clicked on so the jquery library is present and working.
The jquery.js file is in the same folder as the index.php file that is calling it.
What am I doing wrong?
This is the code I have in the external .js file currently just to test it is working(it isn't):
$("document").ready(function(){
$("p").click(function(){
$("p").css("color", "red");
});
});
Problem 1
It looks like jquery.js contains the code you wrote that depends on jQuery.
You need to load jQuery before you try to use it.
Swap the order of the <script> elements.
Problem 2
$("document") will wait for <document> elements to be ready. HTML doesn't have such a thing. Lose the quotes to pass in the document object directly.
Better yet, forget about the explicit call to ready and just
jQuery(function () { /* your function */ });

Categories