Tuesday, 13 January 2015

Using JavaScript Prototype for Object Oriented Approach


Prototype property
Every object in JavaScript has a prototype. This prototype can be seen by accessing __proto__ property in recent modern browsers except IE.
var n = 5;
console.log(n.__proto__);

var myObj = {};
console.log(myObj.__proto__);


Function prototype property
There is another similar term that is quite confusing in JavaScript world, it is the prototype property. This is not the real prototype property like the one above. However this is a property that is found in every function in JavaScript. I prefer to call this property; function prototype.
function Person(firstname, lastname) {
    this.firstname = firstname;
    this.lastname = lastname;
    this.fullName = function () {
        return this.firstName + ' ' + this.lastName;
    }
}
console.log(Person.prototype);

// below will yield 'undefined' because it is not a function
var n = 5;
console.log(n.prototype);

// this will be false as a function prototype is not the same as its prototype property
Person.prototype == Person.__proto__;


Creating object with new keyword
When we initialise a new object with new keyword, the object's real prototype will point to the constructor function's function prototype property.
var john = new Person('john', 'king');

// john's prototype will point to Person's function prototype property
console.log(john.__proto__ == Person.prototype)  // true
The new object will have whatever defined inside the constructor function plus access to whatever in its prototype. So if we add more properties to the constructor function's function prototype, these will be accessible by the created objects. This will be explained more in details below.

A very important rule that need to be remembered from here is:
newObject.__proto__ = TheFunction.prototype


Prototypes chain
In JavaScript, when an object property is called, if it is not found within the object, JavaScript will try to traverse up it's prototypes chain to find it. If it already reaches the root but still cannot find the property, undefined will be returned.
var animal = { name: 'animal', eats: true };

var fish = { name: 'fish', swims: true };
// set fish prototype to animal
fish.__proto__ = animal;

var tuna = { name: 'tuna', canBeCanned: true };
// set tuna prototype to fish
tuna.__proto__ = fish;

console.log(tuna.swims);
console.log(tuna.eats);
Below is the structure created (on Firebug):

As we can see tuna's prototype is fish object and fish's prototype is animal object. The text in bold are properties that are available to the containing objects.


Adding a property to a prototype chain
When we have an established prototypes chain then if we added a new property to one of the prototype objects in the chain, this new property would be accessible by the lower objects in the chain.
// based on the example above we add a new property to animal
animal.moves = true;
console.log(tuna.moves) // lower objects in the chain can access it

// we can also add a new property through a prototype link
// this example below add a new property at animal's level because we have set fish.__proto__ = animal
fish.__proto__.breathes = true;
console.log(tuna.breathes)


Using these prototype behaviours for object oriented approach
Having knowledge of prototype behaviours described above, we can implement object oriented concept in our JavaScript codes. We will also need to use function prototype and new keyword to set up relationships as the __proto__ property is not available in some browsers. As an example, we could have something like this:
function Coder() {
    this.name = 'coder';
    this.code = function () {
        return "coding now";
    }
}

function JSCoder() {
    this.name = 'JSCoder';
    this.writeSomeJSCodes = function () {
        return "writing: this.__proto__ = . . .";
    }
}

// set up the relationship
JSCoder.prototype = new Coder();
// this is saying that every newly created JSCoder object will have its prototype property points to a Coder object

var jack = new JSCoder();
// because we have set above JSCoder.prototype = new Coder()
//  and because of the rule: newObject.__proto__ = TheFunction.prototype
//  then this one below is implemented implicitly when jack is created:
//  jack.__proto__ = JSCoder.prototype  which equals to a Coder object ( new Coder() )

console.log(jack.writeSomeJSCodes());
console.log(jack.code());

// we can also add a new property to a function prototype then it will be accessible by existing child object(s)
JSCoder.prototype.debugging = function () { return 'debugging some codes' };
// this is saying that because of the rule: newObject.__proto__ = TheFunction.prototype
//  when a new JSCoder object is created: var jack = new JSCoder()
//  then this will apply: jack.__proto__ = JSCoder.prototype
//  and JSCoder.prototype has been set to a Coder object ( new Coder() )
//  so when a new property is added,
//  JSCoder.prototype is a Coder object plus the new property
//  thus jack's prototype ( jack.__proto__ ) is a Coder object plus the new property

console.log(jack.debugging());

What will happen if we modify the function prototype to point to a new object? Existing objects will not be affected, however new objects created after the modification will have their prototypes point to the new object.
// modify JSCoder function prototype to point to a new object
JSCoder.prototype = { sing: function () { return 'singing' } };
console.log(jack); // existing objects' prototypes do not change

// however new objects' prototypes will point to the new object
var jim = new JSCoder();
console.log(jim);


References and further readings:
A Plain English Guide to JavaScript Prototypes
Understanding “Prototypes” in JavaScript
Understanding JavaScript Prototypes
Prototypal inheritance
OOP in JS, Part 2 : Inheritance

Monday, 5 January 2015

Implementing Asynchronous Tasks with $q in AngularJS

AngularJS has provided $q service that can be used to implement asynchronous tasks. It uses deferred objects and the promises they return to accomplish asynchronous runs.

A basic example of using $q:
function myAsyncFunc() {
  // create a deferred object
  var deferredObject = $q.defer();

  . . .

  // if for a reason, we want to cancel this task
  if (errorOccured) {
        deferredObject.reject('an error has occured');
        return deferredObject.promise;
  }

  // after the job is completed, call resolve()
  deferredObject.resolve();

  . . .

  // return the promise
  return deferredObject.promise;
}

// then on the caller
myAsyncFunc().then(
  // success (when resolve() was called)
  function() {
    alert('success')
  },
  // error (when reject() was called)
  function(reason) {
    alert('failed: ' + reason)
  }
)

We can also return an object when the task is completed. To do this, just pass the object as an argument to the resolve() function instead of nothing. Below is an example:
function myAsyncFunc() {
  var myObject = . . .
  deferredObject.resolve(myObject);
}

// then on the caller, we can use the passed object
myAsyncFunc().then(
  // success
  function(passedObj) {
    . . .
  }
);

When resolving a deferred object, we can use deep nesting functions if required. As long as the deferred object variable is accessible, this should not be an issue:
var deferredObject; // need to make sure that this deferred object variable will be accessible from inside nesting function

function myAsyncFunc() {
  // create a deferred object
  deferredObject = $q.defer();

  . . .

  nestedOne();

  // return the promise
  return deferredObject.promise;
}

function nestedOne() {
  nestedTwo();
}

function nestedTwo() {
  deferredObject.resolve();
}

Wednesday, 10 December 2014

Some Guidelines to Design Clean Controller and Service

An AngularJS controller should not be burdened with other tasks other than mediating interaction between view and data that comes from one or more services. The data model, data management and application business logic should be written in services. I also like to use controllerAs with 'this' approach. Also include as few services as possible in the controller. If a controller has too many services then this should be questioned. Instead we should try to use services that aggregate other required services inside.

Below is an example of a controller:
myApp.controller('MedicineCtrl', ['medicineService',
 function (medicineService) {
     var vm = this;
     vm.medicineNames = medicineService.medicineNames;
     vm.addMedicine = function (input) {
         medicineService.addMedicine(input);
     };
     vm.updateMedicine = function (input) {
         medicineService.updateMedicine(input);
     };
     vm.deleteMedicine = function (id) {
         medicineService.deleteMedicine(id);
     };
}]);
Of course, this is a simplified example however this should give us a picture of what a controller should be designed like.

For the service, it's recommended to have 'private' variables and functions needed and only expose publicly the ones that are necessary as service object's properties. Also whenever possible, try to design the functions to run asynchronously using AngularJS promise (will show an example in the next post). Below is an example of a service:
myApp.factory('medicineService', ['otherService1', 'otherService2', 
  function (otherService1, otherService2) {
    // 'private' variables and functions
    var _medicines = [];
    var _privateVarOne;
    var _privateVarTwo;
    
    _addMedicine = function (input) {
       . . .
       // some business logic
       . . .
    };

    _updateMedicine = function (input) {
       . . .
       // some business logic
       . . .
    };

    _deleteMedicine = function (id) {
       . . .
       // some business logic
       . . .
    };

    _anotherPrivateFunction = function () {
       . . .
       // some business logic
       . . .
    };

    // only expose publicly the required members
    return {
        medicineNames: _medicineNames,
        addMedicine: _addMedicine,
        updateMedicine: _updateMedicine,
        deleteMedicine : _deleteMedicine 
    }
}]);

Wednesday, 3 December 2014

AngularJS ControllerAs and Scope

If we set up a view and controller with controllerAs like below:
// in routing configuration
. . .
.when('/pageOne', {
        templateUrl: 'partials/page-one.html',
        controller: 'CtrlOne',
        controllerAs: 'vm'
})
. . .
// the controller
userApp.controller('CtrlOne', [function () {
    var vm = this;
    vm.nameOne = "test";
    vm.getName = function () {
        return 'aaa';
    };

    this.nameTwo = "blah";
    var nameThree = "ggg"; // not visible from outside
}]);
then we will have these scopes when the page loads:



The first scope is the root scope and the one underneath it is the scope created for the controller. As the picture shows, the variables are created as properties of 'vm' object. If we had used the traditional approach by defining variables on $scope such as $scope.myVariable = ... then these variables would be created on the first level on controller scope (not wrapped inside an object). We can also see when we use controllerAs, other variable that is defined directly not through 'this' object will not be visible from outside.


Adding a Child Controller

Let us add a child controller inside our controller. The child controller:
userApp.controller('ChildCtrl', [function () {
    var vm = this;
    vm.dataOne = 'sss';
    vm.getData = function () {
        return 'bbb';
    }
}]);
And change our view to be like this:
<div>
    Page One
    <div>
        <div>{{parentVm.nameOne}}</div>
        <div ng-controller="ChildCtrl as childVm">
            {{childVm.dataOne}}
            {{parentVm.nameOne}}
        </div>
    </div>
</div>

Now we can see that a new scope is created for the child controller:




Accessing Parent Controller's Variables

On the view, we can simply use '{{parentVm.variableName}}' to refer to a parent controller's variable.

In the child controller script function, accessing parent's variables which controller uses controllerAs is not as easy as if the parent controller had used $scope to register its properties. One way to do this is by using $scope help in the child controller. We need to inject $scope to the controller then refer to the parent controller's instance name to be able to access its variables/properties. Below is an example:
$scope.parentVm.nameOne = 'modify parent var';
//$scope.$parent.parentVm.nameOne = 'modify parent var';    // or could use $parent
The code on the first line is utilising JavaScript prototypal inheritance where it will try to find the property 'parentVm.nameOne' on the current scope then if it is not found, it will try to find on the parent scope and so on until it reaches the root scope. This AngularJS documentation 'Understanding Scope' explains it in more details.
The second code is finding the property on the parent scope. We could append many $parent if required.

If we had tried to do these below inside child controller:
vm.nameOne = 'modified';
$scope.nameOne = 'hhh';
new variables would be created on the current scope. One is on the scope's root level and the other one is inside an object. The picture below shows this:




Creating Local Variables that Hold References

If we want to create a local variable that holds reference to a variable in parent controller then we need to create that variable as an object in parent controller. This is explained as well in the referred AngularJS documentation above. For example:
// create an object variable in parent controller
vm.objVar = { name: 'aaa' };
then in our child controller:
// create the local variable in child controller
vm.childRefVar = $scope.$parent.parentVm.objVar;

// try to do some update
$scope.$parent.parentVm.objVar.name = 'jjj'; // when we update the variable in parent controller, this will reflect in both parent and local variables
vm.childRefVar.name = 'bbb'; // when we modify the local variable, this will reflect in parent variable as well


Best Practices

As we have seen above, accessing variables in parent controller is not straight forward. If you are going to have nested controllers in your view, it is recommended to use a service to share data between the controllers rather than using variables/properties in your controller.

If you do not want to use a service then I think it is better to register the variables or functions that are going to be shared on $scope rather than on 'this' object unless you are going to decide/know the controller's alias object name in advance to be used from codes inside child controller.

Thursday, 13 November 2014

Cordova Plugin is not Available when Application Starts

If you use a plugin and execute its method when your application starts and have this error:
TypeError: Cannot read property '[your_plugin_name]' of undefined at Object.[plugin_method]
then it is likely that the plugin has not been initialised fully when the method is called.

To solve this issue, wait until deviceready event is fired before calling the plugin's method.

With AngularJS, I like to wait until deviceready event is fired before loading the whole application. To do this, make sure that ng-app declaration is removed from the HTML, then bootstrap the app when deviceready event has fired. document.addEventListener is used to determine whether the event has been fired.
document.addEventListener("deviceready", function() {
    angular.bootstrap(document, ["myApp"]);
}, false);
If you want to apply this to a particular element instead of the whole HTML document (or body), you could use:
var theElement = document.findByID(...) // or document.querySelector(...);
angular.bootstrap(theElement, ["myApp"]);

Then you can call the rest scripts:
var myApp= angular.module('myApp', [. . .]);

myApp.config(
  . . .
);

Thursday, 23 October 2014

Adding ngCordova Plugin to Visual Studio Cordova Project

We will see how to add a plugin from ngCordova which has a collection of Cordova API plugins wrapped in AngularJS. ngCordova will help even more Cordova developers who are using AngularJS.

1. First, include ng-cordova.js or ng-cordova.min.js file into our project structure. We can use bower to install that or download the zip file from its GitHub repository then find the js file inside.

2. On our project main page, add a reference to it before the reference to cordova.js file.
<script src="some_path/ng-cordova.min.js"></script>
<script src="cordova.js"></script>

3. Include 'ngCordova' in our app module. For example:
var myApp = angular.module('myApp', ['ngCordova', . . .]);

4. Add the intended plugin wrapped by <vs:feature></vs:feature> inside <vs:features> node in our project config.xml file like below:
<vs:features>
  <vs:feature>plugin_id@version_number</vs:feature>
  <vs:feature>plugin_2_id@version_number</vs:feature>
  . . .
</vs:features>
Right click config.xml file then select View Code to do this.

To find the plugin Id and version number, we can check from plugins.cordova.io site or from the plugin.xml file on the plugin repository site. However if we are getting the information from plugin.xml file, that will always be the latest version which sometimes is not the stable one.

An example for the latter one, say we would like to use Local Notification plugin. Go to its site https://github.com/katzer/cordova-plugin-local-notifications then open plugin.xml file located on the root. Inside the plugin element there are 'id' and 'version' attributes.

When building the project, Visual Studio will download the plugin and add to the project if it has not done so.


5. Inject the plugin service into our controller then we can start using it.
For example, to use Local Notification, we need to inject $cordovaLocalNotification like this:
myApp.controller('MyCtrl', ['$cordovaLocalNotification', . . . ,
  function ($cordovaLocalNotification, . . .) {
  . . .
}]);

Friday, 10 October 2014

Basic Navigation in Ionic

On this post we will see how to do basic navigation in Ionic Framework.

1. First we need to configure the routes in AngularJS:
app.config(function($stateProvider, $urlRouterProvider) {
  $stateProvider
  .state('home', {
    url: '/',
    templateUrl: 'home.html'
  })
  .state('pageOne', {
    url: '/page1',
    templateUrl: 'one.html'
  })
  .state('anotherPage', {
    url: '/whatever',
    templateUrl: 'myhtml.html'
  });
  
   $urlRouterProvider.otherwise("/");
});
In the example we use UI Router to manage our routes. Each route has a state name, a defined url and an actual path for the view content. In the end, we also define the default url to be called when a url targeted does not match any in configurations.


2. Then on our main page, we just need to use
<ion-nav-view></ion-nav-view>
It will be useful to add a navigation bar with back button and also to have an animation effect like this:
<ion-nav-bar class="bar-positive">
        <ion-nav-back-button class="button-icon ion-arrow-left-c">
        </ion-nav-back-button>
    </ion-nav-bar>

    <ion-nav-view animation="slide-left-right"></ion-nav-view>
When we use Ionic navigation back button, the scripts behind it automatically do the job in storing page histories and pulling out the previous page as well as redirecting to the page when clicking the element.


3. Finally create each partial view using
<ion-view>
  <ion-content>
    . . .
  </ion-content>
</ion-view>


For a complete working example, please see here in Plunker.