5

I am testing with pure JavaScript if browser seems to support HTML5 and if so, I want to load jQuery and then process the rest of page. If not, some redirection will occur.

  <script type="text/javascript">
    var canvas = document.createElement('canvas');
    if (canvas && canvas.getContext && canvas.getContext('2d')) {
      var s = document.getElementsByTagName('script')[0];
      var jq = document.createElement('script');
      jq.type = 'text/javascript';
      jq.src = 'js/jquery.js';
      s.parentNode.insertBefore(jq, s);
    }
    else {
      // ... redirection ...
    }
  </script>
  <script type="text/javascript">
    $(function () {
      //...
    }
  </script>

But the code above is not working properly, because I got error

  Uncaught ReferenceError: $ is not defined

which is clearly saying that jQuery library has not been loaded.

Why? What is wrong with conditional script loading in my code above?

10
  • 1
    I think it is because at parse-time you don't have that variable jQuery $ since you are loading it after the script. you have to add your script dynamically then inside the node too before you insert it then I think it will work fine .. Commented Jul 4, 2013 at 3:09
  • Have you tried to View Source to see if jquery is loaded or properly inside the script element? Could you put your code in jsfiddle? Commented Jul 4, 2013 at 3:12
  • @KevinNacios - Wrong. Commented Jul 4, 2013 at 3:13
  • @Edper - Sorry, I can't publish my entire code. jQuery is loaded, but most likely not at right time... Commented Jul 4, 2013 at 3:14
  • @Ωmega ok I understand. CME64 is in the right direction I believe. Commented Jul 4, 2013 at 3:17

4 Answers 4

4

This is a case where it may make sense to use document.write(). You'd need to put this code in the <body> instead of the <head>:

  <script type="text/javascript">
    var canvas = document.createElement('canvas');
    if (canvas && canvas.getContext && canvas.getContext('2d')) {
      document.write( '<script src="js/jquery.js"><\/script>' );
    }
    else {
      // ... redirection ...
    }
  </script>
  <script type="text/javascript">
    $(function () {
      //...
    }
  </script>

Or, you may be able to use an ordinary <script> tag to load jQuery, but put it after your conditional redirection:

  <script>
    var canvas = document.createElement('canvas');
    if( !( canvas && canvas.getContext && canvas.getContext('2d') ) ) {
      // ... redirection ...
    }
  </script>
  <script src="js/jquery.js"></script>
  <script>
    $(function () {
      //...
    }
  </script>

With either of these approaches, the order of execution is:

  1. The first <script>.
  2. The loading of jquery.js, whether done with document.write() or a simple <script> tag.
  3. The final script.
Sign up to request clarification or add additional context in comments.

7 Comments

Redirection was just an example. It I more complex. I need to force browser to wait for library load before process the other scripts - that is my issue here.
If you use document.write() it is synchronous. Your other scripts will not execute until after that.
@Alan - Yes, I'm familiar with the reasons not to use document.write(). None of them apply here; in fact, at least one of those reasons "not" to use it is exactly the reason why it's a good solution here: the fact that it is synchronous and delays the execution of other scripts that follow it.
@MichaelGeary the "doesn't work with xhtml" reason does apply here. Though, I would say, XHTML is dead.
|
3

When you insert a script tag like you are, it will be loaded in the background, not immediately and thus your next script will run before jQuery is loaded. You will need to attach a listener such that you know when jQuery is successfully loaded and you can then run your scripts that use jQuery.

Here's an article that describes how to know when a dynamically loaded script is loaded: http://software.intel.com/en-us/blogs/2010/05/22/dynamically-load-javascript-with-load-completion-notification.


FYI, in your specific case, you also could just have a static script tag that loads jQuery, but place your script that detects whether to redirect or not BEFORE the jQuery script tag. That would be the simplest option.

<script type="text/javascript">
    var canvas = document.createElement('canvas');
    if (!canvas || !canvas.getContext || !canvas.getContext('2d')) {
        // redirect here or whatever
    }
</script>
<script type="text/javascript" src="jquery.js">
</script>
<script type="text/javascript">
    $(function () {
      //...
    }
</script>

11 Comments

Any chance to add "waiting script" after the dynamic script loading, which would prevent the other scripts to execute? I should not modify existing page that is beyond the check point...
@Ωmega - no, you can't make it wait to load the script when loading the script the way you are. I did add another pretty simple option to my answer though.
As I already wrote in the other comment (see answer from Michael Geary), redirection was just an example, it is more complex.
@Ωmega - then the first part of my answer is the way to do it. You run the rest of your initialization code in a callback function that is called when jQuery is loaded.
I was hoping to find solution which would work without modification of the rest of page content (html, scripts,...)
|
1

finally working like a charm, I'm relieved myself !

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>JS Bin</title>
   <script type="text/javascript">
      window.onload = function(){
        var jqu = "$(console.log('worked'));";
        var canvas = document.createElement('canvas');
        if (canvas && canvas.getContext && canvas.getContext('2d')) {
          var s = document.getElementsByTagName('head')[0];
          var jq = document.createElement('script');
          jq.setAttribute('type','text/javascript');
          jq.innerHTML = jqu;
          var jqLoad = document.createElement('script');
          jqLoad.setAttribute('type','text/javascript');
          jqLoad.setAttribute('src','jquery-1.10.0.js');
          jqLoad.setAttribute('id','jqloader');
          s.appendChild(jqLoad);
          document.getElementById('jqloader').onload = function(){
            console.log('loaded');
            s.appendChild(jq);
          }
        }
        else {
        // ... redirection ...
        }
        console.log(document);
      }
  </script>
</head>
<body>

</body>
</html>

jsbin Demo

explanation :

1- using dom functions to append or insert elements are always the best (dynamic and safer more than anything else), and document.write is not recommended over that.

2- at parse-time, whatever functions you have in your script will be evaluated thus you will get an error if you have the script and not loaded the library yet.

3- loading the library and executing the relevant script in the same tag is not recommended. better do the script in another tag (after loading is done completely) to ensure it will work.

4- events for document.onload ensures that the document is loaded and the doms exist so you can append children to them. as for the document.getElementById('jqloader').onload it was just to insure that the jquery library is loaded completely and added to the document, and only then the script will be added after and evaluated.

Comments

0

As others have said, the reason you're getting an error is because you've loaded jQuery asynchronously and it hasn't loaded yet.

There are two ways to accomplish what you want.

You can poll for window.jQuery, or you can use an asynchronous loader callback.

Since you only load jQuery only when you detect canvas support, you won't have to worry about supporting old browsers.

var async_script_load = function (s, callback) {
    var script;

    script = document.createElement("script");
    script.async = "async";

    if (s.scriptCharset) {
        script.charset = s.scriptCharset;
    }

    script.src = s.url;

    // Attach handlers for all browsers
    script.onload = script.onreadystatechange = function () {
        if (!script.readyState || /loaded|complete/.test(script.readyState)) {
            // Handle memory leak in IE
            script.onload = script.onreadystatechange = null;

            // Remove the script
            if (head && script.parentNode) {
                head.removeChild(script);
            }

            // Dereference the script
            script = undefined;
            callback(200, "success");
        }
    };
    // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
    // This arises when a base node is used (#2709 and #4378).
    head.insertBefore(script, head.firstChild);
};

async_loader({url:'http://tempuri.org/jquery.min.js'},function() {
   //call jquery here.
});

For a polling method, it's as simple as:

var checkJq = function() { 
    if(window.jQuery) {
      //do jQuery
    } else {
       setTimeout(checkJq,100);
    }
}

setTimeout(checkJq,100);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.