============================ Building a JavaScript Module ============================ CKAN makes heavy use of modules to add additional functionality to the page. Essentially all a module consists of is an object with an ``.initialize()`` and ``.teardown()`` method. Here we will go through the basic functionality of building a simple module that sends a "favourite" request to the server when the user clicks a button. HTML ---- The idea behind modules is that the element should already be in the document when the page loads. For example our favourite button will work just fine without our module JavaScript loaded. ::
Here it's the ``data-module="favorite"`` that tells the CKAN module loader to create a new instance for this element. JavaScript ---------- Modules reside in the *javascript/modules* directory and should share the same name as the module. We use hyphens to delimit spaces in both filenames and modules. :: /javascript/modules/favorite.js A module can be created by calling ``ckan.module()``: :: ckan.module('favorite', function (jQuery) { return {}; }); We pass in the module name and a factory function that should return our module object. This factory gets passed a local jQuery object and a translation object. .. Note:: In order to include a module for page render inclusion within an extension it is recommended that you use ``{% asset %}`` within your templates. See the `Assets Documentation <./assets.html>`_ Initialisation ~~~~~~~~~~~~~~ Once ckan has found an element on the page it creates a new instance of your module and if present calls the ``.initialize()`` method. :: ckan.module('favorite', function (jQuery) { return { initialize: function () { console.log('I've been called for element: %o', this.el); } }; }); Here we can set up event listeners and other setup functions. :: initialize: function () { // Grab our button and assign it to a property of our module. this.button = this.$('button'); // Watch for our favourite button to be clicked. this.button.on('submit', jQuery.proxy(this._onClick, this)); }, _onClick: function (event) {} Event Handling ~~~~~~~~~~~~~~ Now we create our click handler for the button: :: _onClick: function (event) { event.preventDefault(); this.favorite(); } And this calls a ``.favorite()`` method. It's generally best not to do too much in event handlers it means that you can't use the same functionality elsewhere. :: favorite: function () { // The client on the sandbox should always be used to talk to the api. this.sandbox.client.favoriteDataset(this.button.val()); } Internationalisation ~~~~~~~~~~~~~~~~~~~~ See :ref:`javascript_i18n`. Notifications ~~~~~~~~~~~~~ This submits the dataset to the API but ideally we want to tell the user what we're doing. .. code-block:: javascript favorite: function () { this.button.text('Loading'); // The client on the sandbox should always be used to talk to the api. var request = this.sandbox.client.favoriteDataset(this.button.val()) request.done(jQuery.proxy(this._onSuccess, this)); }, _onSuccess: function () { // Notify allows global messages to be displayed to the user. this.sandbox.notify('Done', 'success'); } Options ~~~~~~~ Displaying an id to the user isn't very friendly. We can use the ``data-module`` attributes to pass options through to the module. ::