Note: You are currently viewing documentation for Moodle 2.0. Up-to-date documentation for the latest stable version is available here: Javascript and YUI 3 FAQ.

Javascript and YUI 3 FAQ: Difference between revisions

From MoodleDocs
(New page: {{Moodle 2.0}}A quick primer on the internals of Moodle's javascript, and how to use YUI within it. Based on [http://moodle.org/mod/forum/discuss.php?d=168157 formlibs plus ajax] discussio...)
 
(made all sections level 2 headings)
Line 1: Line 1:
{{Moodle 2.0}}A quick primer on the internals of Moodle's javascript, and how to use YUI within it. Based on [http://moodle.org/mod/forum/discuss.php?d=168157 formlibs plus ajax] discussion in the General Developer forum.
{{Moodle 2.0}}A quick primer on the internals of Moodle's javascript, and how to use YUI within it. Based on [http://moodle.org/mod/forum/discuss.php?d=168157 formlibs plus ajax] discussion in the General Developer forum.


=== How do I add an event to make changing a value in a select control submit its parent form? ===
== How do I add an event to make changing a value in a select control submit its parent form? ==


When you put the field's name in addElement, it automatically gives it an ID. Say you called it "select1", the id would be "id_select1". There's an exception to this (I can't remember which element it is) in which case you'll need to define an id in the attributes.
When you put the field's name in addElement, it automatically gives it an ID. Say you called it "select1", the id would be "id_select1". There's an exception to this (I can't remember which element it is) in which case you'll need to define an id in the attributes.
Line 13: Line 13:
  }</code>
  }</code>


=== How do I get that into the page. Is that a 'yui' call or a 'requires_js" call or whatever? ===  
== How do I get that into the page. Is that a 'yui' call or a 'requires_js" call or whatever? ==  


The best documentation to read is here: [[Development:JavaScript_guidelines]]
The best documentation to read is here: [[Development:JavaScript_guidelines]]
Line 19: Line 19:
Essentially, you need to define M.your_plugin as an object in a javascript file. You then define the submit_form() function as a method of M.your_plugin, and put the Y.on() call in the init method of the object. You then include the javascript file with $PAGE->requires_js() and call the init method with js_init_call (see docs).
Essentially, you need to define M.your_plugin as an object in a javascript file. You then define the submit_form() function as a method of M.your_plugin, and put the Y.on() call in the init method of the object. You then include the javascript file with $PAGE->requires_js() and call the init method with js_init_call (see docs).


=== Also, where does the 'Y' get defined? Is this documented somewhere (I can't find anything)? ===
== Also, where does the 'Y' get defined? Is this documented somewhere (I can't find anything)? ==


Y is a bit complicated, it took me a while to really understand what happens, but here's a brief explanation:
Y is a bit complicated, it took me a while to really understand what happens, but here's a brief explanation:
Line 35: Line 35:
You may also find this page useful (or more confusing ) [[Development:How_to_create_a_YUI_3_module]]
You may also find this page useful (or more confusing ) [[Development:How_to_create_a_YUI_3_module]]


=== The M.your_plugin thing. What if it isn't a module? What if it's a report somewhere or a local plugin. What's the syntax for this thing? I guess the 'M' is just an arbitrary "thing" ===
== The M.your_plugin thing. What if it isn't a module? What if it's a report somewhere or a local plugin. What's the syntax for this thing? I guess the 'M' is just an arbitrary "thing" ==


First of all, dismbiguation of terms:
First of all, disambiguation of terms:


* A ''YUI Module'' is subset of YUI functionality, contained in it's own namespace, e.g Y.Node
* A ''YUI Module'' is subset of YUI functionality, contained in it's own namespace, e.g Y.Node
Line 55: Line 55:
The actual "core" javascript code to do this would look something like:
The actual "core" javascript code to do this would look something like:


<code javascript>YUI.use('required', 'yui', 'modules', function(Y) {  
<code javascript>
YUI.use('required', 'yui', 'modules', function(Y) {  
     // YUI.use initialises Y with required modules,  
     // YUI.use initialises Y with required modules,  
     // and passes it to an anonymous function.
     // and passes it to an anonymous function.
Line 61: Line 62:
     M.block_blockname.init_function(Y);
     M.block_blockname.init_function(Y);
     M.report_reportname.init_function(Y, other, parameters);
     M.report_reportname.init_function(Y, other, parameters);
  });</code>
  });
</code>


=== How does Y relate to the yui docs? To step back, how do I work out what methods etc. Y has that I can use? ===
== How does Y relate to the yui docs? To step back, how do I work out what methods etc. Y has that I can use? ==


When you request a module for inclusion, it's classes will be attached to the Y namespace. You can see it's classes by going to the YUI documentation for that module, and looking at the API docs. Each module's classes then has a set of properties and methods.
When you request a module for inclusion, it's classes will be attached to the Y namespace. You can see it's classes by going to the YUI documentation for that module, and looking at the API docs. Each module's classes then has a set of properties and methods.

Revision as of 19:18, 8 February 2011

Template:Moodle 2.0A quick primer on the internals of Moodle's javascript, and how to use YUI within it. Based on formlibs plus ajax discussion in the General Developer forum.

How do I add an event to make changing a value in a select control submit its parent form?

When you put the field's name in addElement, it automatically gives it an ID. Say you called it "select1", the id would be "id_select1". There's an exception to this (I can't remember which element it is) in which case you'll need to define an id in the attributes.

You'll then want to get the select and the form using YUI, and attach an event listener:

Y.on('change', submit_form, '#select1');

function submit_form() {    
   var form = Y.one('#mform1'); // The id for the moodle form is automatically set.
   var form.submit();
}

How do I get that into the page. Is that a 'yui' call or a 'requires_js" call or whatever?

The best documentation to read is here: Development:JavaScript_guidelines

Essentially, you need to define M.your_plugin as an object in a javascript file. You then define the submit_form() function as a method of M.your_plugin, and put the Y.on() call in the init method of the object. You then include the javascript file with $PAGE->requires_js() and call the init method with js_init_call (see docs).

Also, where does the 'Y' get defined? Is this documented somewhere (I can't find anything)?

Y is a bit complicated, it took me a while to really understand what happens, but here's a brief explanation:

Y is a namespace generated when YUI is initialised containing the methods from all the loaded modules. Internally, moodle initialises Y and passes it to the module's init function in js_init_call, as the first parameter. To access Y from your init function, you need to do this:

M.my_plugin.init = function(Y) { //Y is now accessible in the scope of init(). However, you probably want access Y in your object's other method's too, so you need to do something like this:

M.my_plugin.init = function(Y) { //Y is now accessible in the scope of init().

   this.Y = Y; // this.Y is now accessible from all methods of M.my_plugin
}

For tidiness, I always start any other method using Y with "var Y = this.Y" so I don't have to keep prefixing with this.

You may also find this page useful (or more confusing ) Development:How_to_create_a_YUI_3_module

The M.your_plugin thing. What if it isn't a module? What if it's a report somewhere or a local plugin. What's the syntax for this thing? I guess the 'M' is just an arbitrary "thing"

First of all, disambiguation of terms:

  • A YUI Module is subset of YUI functionality, contained in it's own namespace, e.g Y.Node
  • A Moodle Module, I'm sure you understand.
  • A Javascript Module in this context, is a subset of javascript functionality contained in it's own M. namespace.

Any Moodle plugin can define it's own Javascript Module, whether it's a Moodle Module or a different type of plugin. Usually this will be in the plugin's module.js file, and be called M.plugintype_pluginame (similar to the lang file naming convention), but the object passed as the 4th parameter of $PAGE->requires->js_init_call() allows you to customise this.

A good example of Y's usage that I can point you to is my quickfindlist block.

Take a look at the bottom of get_content() in block_quickfindlist.php. This defines $jsmodule (the Javascript module's parameters, including the name, the file it's stored in, and the YUI modules it needs), $jsdata (extra parameters to pass with the init call, in addition to Y), and then passes them, along with the name of the module's init function, to js_init_call(). Note that as it's a block, it uses $this->page in place of $PAGE.

Now look at module.js. It defines M.block_quickfindlist (which is the module we specified with $jsmodule) and the init() method (which we referenced in js_init_call()). init accepts 6 parameters: Y, and the 5 set in $jsdata. It then stores a copy of Y in M.block_quickfindlist.Y so it can be used in other methods, and uses Y itself to call Y.on(), adding event listeners to the block. M.block_quickfindlist.search() is defined futher down module.js - it needs acces to Y too, so we create a copy in the method's scope for easy referencing, before using it to make an AJAX request with Y.io(). You can also see use of M.cfg, another Javascript Module, to access the value of wwwroot.

An important thing to note about Y being used all over the place is that as I understand it, Y is only initialised once with all the YUI Modules required by any Javascript Modules on the current page (hence the requirements manager). It's then passed to each module's init function, so they can use it in their own scope.

The actual "core" javascript code to do this would look something like:

YUI.use('required', 'yui', 'modules', function(Y) {

   // YUI.use initialises Y with required modules, 
   // and passes it to an anonymous function.
   // Y is then available to pass to our own init functions
   M.block_blockname.init_function(Y);
   M.report_reportname.init_function(Y, other, parameters);
});

How does Y relate to the yui docs? To step back, how do I work out what methods etc. Y has that I can use?

When you request a module for inclusion, it's classes will be attached to the Y namespace. You can see it's classes by going to the YUI documentation for that module, and looking at the API docs. Each module's classes then has a set of properties and methods.

For example the IO module contains the io class. So telling Moodle that your javascript module requires io will give you access to Y.io and all of its methods. In general, reading the YUI module's documentation and it's examples will give you a good general idea of how to use it's functionality.

It's also worth noting that some modules will create a shortcut method attached directly to Y for convenience. For instance Y.io.io() can also be called using Y.io(), and Y.Node.one() can be called using Y.one().

I'm guessing that some YUI modules are loaded by default ('base' and 'node' probably are), but the requirements manager should make sure that each one's only loaded once. I always define all the YUI Modules my Javascript Module needs, just to make sure.

See also