Jquery not loading before local plugin

Jquery not loading before local plugin

by Kimber Warden -
Number of replies: 3

I'm creating a local plugin walkthrough tutorial for my site, and it's working as it's supposed to. The problem is when I try to add a jquery function to some echoed html, I get an error that says, "ReferenceError: $ is not defined." That means that jquery hasn't loaded yet, right? But how can I make it load sooner? Am I loading it incorrectly?

This is how the plug-in works:

lib.php calls SKOTour.php, which creates an html ordered list whose visibility is then manipulated by SKOTour.js. The .js file is a jquery plugin and it loads and works properly. It's the jquery in the html ordered list that's giving me problems. I get the error immediately on refresh, before any of the page is visible onscreen.


I'm using Moodle 2.9 and a child of the BCU theme


My lib.php file basically contains:

defined('MOODLE_INTERNAL') or die;

global $CFG, $PAGE, $USER;

$PAGE->requires->jquery();

$PAGE->requires->jquery_plugin('SKOTour', 'local_tutorial');

require_once($CFG->dirroot . '/local/tutorial/SKOTour.php');


My SKOTour.php file basically contains:

global $CFG, $PAGE;

$PAGE->requires->jquery();

echo '<ol>

          <li>

        <h2>Collapse Blocks</h2>

        <p>To save screen space, you can collapse a block. Click the button now.</p>

        <p id="AfterClick1">You collapsed it! Click the button again.</p>

        <p id="AfterClick2">You expanded it again!</p>

       <script type="text/javascript">

             $(document).ready(function(){   <-----HERE IS WHERE THE ERROR IS GENERATED

                   $("img.block-hider-hide").click(function(){

                          $("p#AfterClick1").show(500);

                    });

             $("img.block-hider-show").click(function(){

                         $("p#AfterClick2").show(500);

                });

         });

        </script>

      </li>   

</ol>';


SKOTour.js basically contains:

window.onload = (function ReadyTutorial() {     

   RunCourseTutorial();


function RunCourseTutorial() {

   // all my code to "do stuff"

   }

});

Average of ratings: -
In reply to Kimber Warden

Re: Jquery not loading before local plugin

by Andrew Lyons -
Picture of Core developers Picture of Moodle HQ Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers Picture of Testers

Hi Kimber,

Please see the documentation on Javascript Modules at https://docs.moodle.org/dev/Javascript_Modules

Essentially you need to wrap your JS in AMD code.

Hope this helps,

Andrew

In reply to Andrew Lyons

Re: Jquery not loading before local plugin

by Kimber Warden -

I did read that, and frankly, it was over my head. The documentation says that the old methods of including jquery still work, so that's what I'm attempting to do. 

Jquery loads in my theme, but local plugins apparently load before the theme, and I can't figure out why using $PAGE->requires->jquery() in local/plugin/lib.php and also in the .php file that actually uses the jquery doesn't load it in time. Have I misunderstood the documentation? What am I doing wrong?

In reply to Kimber Warden

Re: Jquery not loading before local plugin

by Andrew Lyons -
Picture of Core developers Picture of Moodle HQ Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers Picture of Testers

Hi Kimber,

I believe that the reason you're not seeing jQuery is because you're not calling the page header in your output.

If you look at a typical Moodle PHP file, you'll see that it does a couple of things:

  1. require the config.php file
  2. login and capability checks
  3. outputs the page header
  4. outputs the content
  5. outputs the page footer

If you don't output the header then we don't output the main HTML structure (e.g. the head, title, CSS, base JavaScript, etc.).

I would still recommend looking at the AMD loading mechanisms.

There are two stages to loading JS in Moodle:

  1. in the header we load the YUI, and requireJS loaders, and the jQuery code; and
  2. in the footer we make use of those loaders.

We generally don't advise using jQuery without using the loader.

Typically a use of the requireJS loader looks something like:

require(['local_foo/yourjsfilename'], function(amd) { amd.init([]); });

It's just a really basic use of the loader to load some other code which actually does the work.

To generate this, you need to have something in your PHP call:

$PAGE->requires->js_call_amd('local_foo/yourjsfilename', 'init');

In your JS file, which will be located at local/foo/amd/src/yourjsfilename.js, you write:

require(['jquery'], function($) {
  return {
    init: function() {
      // Your code here.
    }
  }
});

So essentially, in your case, you need to

  1. create the directory structure: local/tutorial/amd/src/
  2. create a file in that src folder (e.g. tutorial.js) and put the bigger block above in it, replacing 'Your code here.' with your code
  3. modify your file to include your code using the PAGE->requires code above.

Voila,

Andrew