9

I cannot wrap my head around this issue and the vast offer of information I found on the net:

On my project the JQuery is loaded with "defer". This I cannot change due to project standards.

<script defer src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js'></script>

Now I need to add some small functions to a page (currently inline):

With this setup the browser will try to execute the inline scrip before jQuery loads => "Uncaught ReferenceError: $ is not defined"

<body>
...
...
<script>
  $("#city").change(function() {...some stuff...};
  $("#doctor").change(function() {...some stuff...};
</script>
</body>

Whats the smart way to resolve this?

Mohit Tanwani
  • 6,608
  • 2
  • 14
  • 32
caliph
  • 1,389
  • 3
  • 27
  • 52
  • Have the script execute a callback which activates an IIFE that executes the javascript? – roberrrt-s Aug 29 '16 at 12:37
  • 1
    Add a regular `onload` callback? See http://stackoverflow.com/questions/27300058/window-onload-vs-script-defer – kennytm Aug 29 '16 at 12:41
  • I tried to wrap it all in a window.onload=function(){...} but this cripples the $(selector).change() functions..(I do not understand why..) – caliph Aug 29 '16 at 12:48

3 Answers3

22

Wrap it inside window.onload, so the script will only be executed when everything is fully loaded.

Try this example:

window.onload = function () {
    $("#city").click(function() {
        alert('city');
    });
    $("#doctor").click(function() {
        alert('doctor');
    });
}
<script defer src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js'></script>

<button id="city">City</button>
<button id="doctor">Doctor</button>

Explanation about window.onload from MDN:

The load event fires at the end of the document loading process. At this point, all of the objects in the document are in the DOM, and all the images, scripts, links, and sub-frames have finished loading.

https://developer.mozilla.org/en/docs/Web/API/GlobalEventHandlers/onload


For more idiomatic (in jquery) way, use the code below. it's the same with window.onload.

$(document).ready(function() {
    // put code here
});

Another alternative, use $(function() { }).

$(function() {
    // put code here
})
novalagung
  • 10,905
  • 4
  • 58
  • 82
  • 2
    Bit late to the party but the doc ready using jquery doesn't work. The problem is that $ is undefined before jqueury is loaded so you can't use it to wait for it to be loaded. I took your snippet and replaced the window.onload withh doc ready and got the exact same error that's in the OP. Window.onload works fine though. – Jag Jan 08 '20 at 16:15
  • 1
    Awesome! Thank you so much. It perfectly solved the broken inline JS on my WordPress website after enabling some Async plugin to improve the speed. I was only finding complex solutions. – eArmin Oct 08 '20 at 18:51
  • 1
    Thank you so much. My code was not working anymore after an update on an symfony webpack project. JQuery will now be loaded as "defer" so later than anything else. So your "window.onload = function () {" helped. Big thank you! – CasualBen Apr 20 '21 at 08:55
  • @DasBen glad to hear that :) – novalagung Apr 20 '21 at 17:42
1

Pros: With this approach, you don't have to wait for the 'load' event to trigger.. this should execute as soon as jQuery has finished loading.

var initInterval = setInterval(function(){
        if(window.jQuery) {
            clearInterval(initInterval);
            init(); // where init is the entry point for your code execution
        }
    }, 20);


function init(){
  $('#example').text('Ahoy!');
}
<script defer src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js'></script>

<div id="example">Hi</div>
Lucky Soni
  • 6,811
  • 3
  • 38
  • 57
1

This way you can add multiple functions to window.load:

window.addEventListener("load",function(event) {
    $("#city").click(function() {
        alert('city');
    });
},false);

window.addEventListener("load",function(){
    $("#doctor").click(function() {
        alert('doctor');
    });
},false);
datasn.io
  • 12,564
  • 28
  • 113
  • 154