Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Moodle Mobile 2 (Ionic 1) Developing a plugin tutorial

From MoodleDocs
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.


Warning: This page is no longer in use. The information contained on the page should NOT be seen as relevant or reliable.



Warning: This page is no longer in use. The information contained on the page should NOT be seen as relevant or reliable.


IMPORTANT: This documentation will be obsolete in May 2018, please read this announcement.

Introduction

This tutorial describes all the steps needed for developing an add-on for the Moodle Mobile app.

In this tutorial we make the following assumptions:

  • You have a medium/good skills/understand of AngularJS/Ionic, PHP and Moodle architecture
  • You know what a Web Service is and how it works in Moodle
  • The plugin you are going to develop requires a Web Service in your Moodle installation to work

There is a second part of this tutorial where we extend the add-on features Moodle Mobile Developing a plugin tutorial part 2

Add-on spec

We want to develop a plugin that will display a new button in the user profile for adding new notes to the user. This plugin is suitable for course managers of teachers.

A couple of screenshots with the desired result:

Initial view
Course contents view

Steps

Set up your development environment

Please, read Setting up your development environment for Moodle Mobile 2

Set up your Moodle installation

Enable debugging, disable caches, etc... the typical settings for developing.

Enable the Mobile Service via Admin / Plugins / Web Services / Mobile

Develop the Moodle Web Services you are going to need

In this case we'll use an existing web service (core_notes_create_notes) that is already available in the Moodle Mobile app service, if you need custom functions you will need to develop a local plugin including there your new Web Services (see https://moodle.org/plugins/view/local_wstemplate) and create a custom service.

Develop the Moodle Mobile add-on

The full source code can be found here: https://github.com/moodlehq/moodlemobile2/tree/master/www/addons/notes

www/addons/notes/main.js

angular.module('mm.addons.notes', [])

.run(function($mmUserDelegate, $mmaNotesHandlers) {

    $mmUserDelegate.registerPlugin('mmaNotes:addNote', $mmaNotesHandlers.addNote);

});

Here we declare the plugin, and register the Plugin (this means that the plugin will be displayed in the User profile.

We will use the $mmaNotesHandlers service for holding all the code related to the plugin availability and main functions

There are more delegates for registering your plugin, see:

  • www/addons/mod_forum/main.js (Module delegate, and module actions delegate)
  • www/addons/messages/main.js (Main side menu delegate, and multiple delegates for the user profile)

www/addons/notes/services/handlers.js

self.isEnabled = function() {
    return $mmaNotes.isPluginEnabled();
};

self.isEnabledForUser = function(user, courseId) {
   // Active course required.
   return courseId && user.id != $mmSite.getUserId();
};

These are mandatory functions that will check our plugin availability, the first one will rely in the $mmaNotes service (isPluginEnabled function), the second ones checks that the user profile is being viewed inside a course (because the WS requires it) and that the current user is not the required user (so you don't see the buttons in your own profile).

        self.getController = function(user, courseid) {

            return function($scope) {

                // Button title.
                $scope.title = 'mma.notes.addnewnote';

                $ionicModal.fromTemplateUrl('addons/notes/templates/add.html', {
                    scope: $scope,
                    animation: 'slide-in-up'
                }).then(function(m) {
                    $scope.modal = m;
                });

                $scope.closeModal = function(){
                    $scope.modal.hide();
                };

                $scope.addNote = function(){
                    // Freeze the add note button.
                    $scope.processing = true;

                    $mmaNotes.addNote(user.id, courseid, $scope.note.publishstate, $scope.note.text).then(function() {
                        $translate('mma.notes.eventnotecreated').then(function(str) {
                            $ionicLoading.show({
                                template: str,
                                duration: 2000
                            });
                        });
                    }, function(error) {
                        $mmUtil.showErrorModal(error);
                    }).finally(function() {
                        $scope.closeModal();
                    });
                };

                $scope.action = function($event) {
                    $event.preventDefault();
                    $event.stopPropagation();

                    $scope.note = {
                        publishstate: 'personal',
                        text: ''
                    };
                    $scope.processing = false;

                    $scope.modal.show();
                };
            };
        };

These is the main function code, it does the following:

  • $scope.title = 'mma.notes.addnewnote'; This sets the button title, note that we reference to the addnewnote string that is in the www/addons/notes/lang/en.json file (we need to prefix the string id to identify the plugin)
  • $ionicModal.fromTemplateUrl - Creates the modal we are going to use for displaying the form, the HTML code of the form is in www/addons/notes/templates/add.html
  • $scope.closeModal - Helper function for closing the modal inside the modal via a button
  • $scope.addNote - This function will be called when the user clicks the "Add a note" button in the modal, it will use the $mmaNotes service that handles all the logic WS logic for creating the note
  • $scope.action - This function will be called when the user clicks the "Add a note" button in the user profile view, it will open the modal and set the default values

www/addons/notes/services/notes.js

angular.module('mm.addons.notes')

.factory('$mmaNotes', function($mmSite, $log, $q) {
    $log = $log.getInstance('$mmaNotes');

    var self = {};

    self.addNote = function(userId, courseId, publishState, noteText) {
        var data = {
            "notes[0][userid]" : userId,
            "notes[0][publishstate]": publishState,
            "notes[0][courseid]": courseId,
            "notes[0][text]": noteText,
            "notes[0][format]": 1
        };
        return $mmSite.write('core_notes_create_notes', data);
    };

    self.isPluginEnabled = function() {
        var infos;

        if (!$mmSite.isLoggedIn()) {
            return false;
        } else if (!$mmSite.canUseAdvancedFeature('enablenotes')) {
            return false;
        } else if (!$mmSite.wsAvailable('core_notes_create_notes')) {
            return false;
        }

        return true;
    };

    return self;
});

This file contains the notes service:

  • isPluginEnabled - Checks if the notes functionality is available by checking Moodle settings and the required WS availability
  • addNote - Will call the remote WS for adding the note via the $mmSite.write helper method (the $mmService has also a read method for retrieving data)

/www/addons/notes/templates/add.html

<ion-modal-view class="product edit create">
    <form name="itemEdit" ng-submit="addNote()">
        <ion-header-bar class="bar-header">
            <h1 class="title">{{ 'mma.notes.addnewnote' | translate }}</h1>
            <a class="button" ng-click="closeModal()">{{ 'mm.core.cancel' | translate }}</a>
        </ion-header-bar>
        <ion-content has-bouncing="true">
            <div class="row">
                <div class="col">
                    <label class="item item-input item-select">
                        <div class="input-label">
                          {{ 'mma.notes.publishstate' | translate }}
                        </div>
                        <select ng-model="note.publishstate" name="publishstate">
                            <option value="personal">{{ 'mma.notes.personalnotes' | translate }}</option>
                            <option value="course">{{ 'mma.notes.coursenotes' | translate }}</option>
                            <option value="site">{{ 'mma.notes.sitenotes' | translate }}</option>
                        </select>
                    </label>
                </div>
            </div>
            <div class="row">
                <div class="col">
                    <label class="item item-input text">
                        <textarea placeholder="{{ 'mma.notes.note' | translate }}" rows="5" ng-model="note.text" name="text" lose-focus-on-return required="required"></textarea>
                    </label>
                </div>
            </div>
            <div class="padding">
                <button type="submit" class="button button-block" ng-disabled="processing || !note.text.length || note.text.length < 2">
                    {{ 'mma.notes.addnewnote' | translate }}
                </button>
            </div>
        </ion-content>
    </form>
</ion-modal-view>

This file includes the code for the modal. As you can see the close button will call the closeModal() function meanwhile the Add a note button will submit the form that will invoke the addNote function

For more information, refer to http://ionicframework.com/docs/api/service/$ionicModal/

See also

Moodle Mobile Developing a plugin tutorial part 2