OU blog

Personal Blogs

AMD JavaScript presentation

Visible to anyone in the world
Edited by Sam Marshall, Wednesday, 16 Sep 2015, 18:24

We are now developing against Moodle 2.9, which means the new 'AMD' method for including JavaScript in Moodle plugins is available to us. (I mentioned this in my last blog post.)

The good news is that it's a lot simpler than previous methods for including JavaScript. The bad news is that it's still a change that developers need to understand, and the Moodle documentation is a bit hard to follow.

So I gave a short introductory presentation for OU developers about how to use this new method. And In case anybody else would be interested, I've attached my slides here as a PDF.

A few details mention OU things but most of it would be applicable to all Moodle developers. (To be clear, this is an introduction and doesn't get into advanced details like performance or whatever.)


Permalink Add your comment
Share post

Moodle JavaScript (jQuery, AMD) for 2.8 developers

Visible to anyone in the world
Edited by Sam Marshall, Thursday, 11 Jun 2015, 12:13

This post is strictly for Moodle developers. If you're not a developer you can stop reading now as this is entirely technical - sorry about that. smile

In Moodle 2.9 the preferred way to write JavaScript is using jQuery and a module framework called AMD. This is documented in the Javascript Modules page of the Moodle developer documentation.

So what if you're writing a new plugin now, which currently has to run in 2.8, but you'd like to update it for 2.9 later with minimal work?

I did a hack to make this work (sort of). In case anyone else is interested, here's how...

1. Wrote my JavaScript using the 'new' approach, so that it begins:

define(['jquery'], function($) {

(For the purpose of this development, I can't currently specify any dependencies other than 'jquery' here; it's hard-coded.)

2. Added a simple wrapper that simulates the AMD module framework without implementing any of it. I put this in a file called define.js. Because this is all done within my plugin, I named the global variables according to my plugin's name. Here it is:

window.format_oustudyplan_modules = {};
window.format_oustudyplan_pending = [];
window.define = function(ignored, fn) {
    window.format_oustudyplan_pending.push(fn($));
};
window.format_oustudyplan_add_pending = function(module) {
    var next = window.format_oustudyplan_pending.shift();
    window.format_oustudyplan_modules[module] = next;
};
window.require = function(modules, fn) {
    var params = [];
    for (var i = 0; i < modules.length; i++) {
        params.push(window.format_oustudyplan_modules[modules[i]]);
    }
    fn.call(this, params);
};

3. Wrote a PHP function to 'load a module':

    public static function load($module) {
        global $PAGE;

        if (!self::$donefirst) {
            $PAGE->requires->jquery();
            $PAGE->requires->js(new \moodle_url('/course/format/oustudyplan/js/define.js'));
            self::$donefirst = true;
        }
        $PAGE->requires->js_init_code('format_oustudyplan_add_pending("' . $module . '");');
        $PAGE->requires->js(new \moodle_url('/course/format/oustudyplan/js/' . $module . '.js'));
    }

4. Wrote another one to 'call a module function':

    public static function call($module, $fn, array $params = array()) {
        global $PAGE;

        $jsparams = '';
        foreach ($params as $param) {
            if ($jsparams !== '') {
                $jsparams .= ',';
            }
            if (is_int($param)) {
                $jsparams .= $param;
            } else if (is_string($params)) {
                $jsparams .= '"' . addslashes_js($param) . '"';
            } else {
                throw new \coding_exception('Unexpected JS param');
            }
        }
        $PAGE->requires->js_init_code(
                'window.format_oustudyplan_modules.' . $module .'.' . $fn . '(' . $jsparams . ')');
    }

5 To include my JavaScript, I do this (the above two functions were in a 'js' class):

            js::load('sections');
            js::call('sections', 'init');

These PHP functions are not the same syntax as used in the 'real' function which is a single function js_call_amd, but are similar. The intention of this approach is that I should be able to move to 2.9 syntax without having to change my JavaScript code. What I will have to do:

  • Delete the PHP code above.
  • Move the JavaScript into the appropriately-named directory and update it using Grunt.
  • Change my loader code to use js_call_amd.

Hope this might be useful to somebody else smile

Permalink Add your comment
Share post

This blog might contain posts that are only visible to logged-in users, or where only logged-in users can comment. If you have an account on the system, please log in for full access.

Total visits to this blog: 227949