Wednesday, July 30, 2014

Where is Model in AngularJS

We all know that Angular follows MV* design pattern and in this pattern M stands for Model. But where is the Model in AngulaJS. In all the demos and samples we see the model mysteriously disappeared. Some people claim that $scope is the model. This may not be correct on how you look at the model.

Before going further let’s check the definition of model. Here is the definition from Microsoft on model

Model. The model manages the behavior and data of the application domain, responds to requests for information about its state (usually from the view), and responds to instructions to change state (usually from the controller).

So a model should include a stateful object along with business and validation logic. Most of the times model also includes the data access layer. In case of Angular the data access layer is a RESTful call. Currently in most of the apps controller is doing the model’s responsibility. Most controllers persist the state (sometimes in $scope) and these controllers perform the data fetching and validation. This is ok for a trivial demo or for small applications. But for complicated or large applications we need clear separation of concerns and hence cannot convolute controllers with the model functionality.

If you see ASP.NET MVC, the model includes only a stateful POCO object and validations. As per the design pattern this is may not appear as the true implementation of model. Our model should include business and data access. In large ASP.NET MVC projects we typically have business and data layers. Hence our model actually consists of a stateful object with business and data layers. So our model was split into multiple files, a stateful object and a business object. Let’s extend the same to AngularJS

Putting “M” back in Angular

Similar to ASP.NET MVC let’s split our model into two files, one contains the stateful object and another a service which acts as business and data layer. In our next section we will move the stateful object to the right place where it belongs.

Let’s assume that we are working on a project where we are using contacts. With that premise let’s create a stateful object called contactModel.js with the following code

'use strict'

angular.module('ngmodels').value("contactModel", contactModel());

function contactModel() {
    return {
        ContactID: 21,
        FirstName: 'Praval',
        LastName: 'Pattam'
    };
}

In the above code we defined an angular value that contains a model with ID, FirstName and LastName properties. Next let’s define an angular service that performs business rules. Here is the sample code:

'use strict'

angular.module('ngmodels').factory('contactService', contactService);
contactService.$inject = ['contactModel'];


function contactService(contactModel) {
    return {
        get: get,
        save: save
    }

    function get() {
        //fetching the contacts
        return contactModel

    }
 

    function save() {
        //saving the contacts
    }
}

As you see our contactModel and contactService together form the Model. With this approach we can use this model in our controller. Let’s see how our controller looks like:

'use strict';

angular.module('ngmodels').controller('contact', contact);
contact.$inject = ['contactService'];

function contact(contactService) {

    var vm = {
        model: {},
        save: save
    };

    initialize();

    return vm;

    function initialize() {
        vm.model = contactService.get();
    }

    function save() {
        contactService.save(vm.model);
    }

}

As you see in the above code we are injecting the contactService (which is part of our model) and our controller passes this model to the view using viewmodel pattern.

Now with our Model we were able to clearly separate the layers and made our controller clean.

In most of the applications we bring the data from the server using a RESTful call. The web server fetches the data from database, executes business logic and returns it as a JSON object. So in our server we typically define a contact object that holds the contact data and sends it back. Here is the definition of the Contact class in C# that is returned to Angular using WebAPI

    public class ContactModel
    {
        public int ContactID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

When this object is returned as JSON, JavaScript automatically creates a stateful object. This will remove the need of defining the contactModel in javascript. With the server side model, our contactService will be changed to use resources to fetch the model from server using the below code.

'use strict'

angular.module('ngmodels').factory('contactService', contactService);

contactService.$inject = ['$resource'];

function contactService($resource) {
    return $resource(
        "/api/contact"
    );
}

So sometimes it is argued that in Angular the model resides on the server. The client uses that server model in the view. But as explained earlier, model contains two pieces. In Angular the definition of the stateful model resides on the server and some part of the data and business resides on the client. Hence the model resides in two layers. It’s funny as it sounds but that is correct.

As you have seen Model is a complex piece in Angular.

You can download the sample code used in this blog from my github site.

5 comments:

  1. Your example of model is as trivial as the demos you are pointing to. If there's no business logic inside the model why have them? Even if there's business logic why would someone not prefer to keep it on the server side away from prying eyes, instead of keeping it on the JS easily visible using browser developer tools? How different will your server side model be from the client side one? Yes you can put models, DTO and what not in each layer in the name of separation of concerns and made it a very complex, unmaintainable and ugly application. Best of luck!

    ReplyDelete
  2. Thanks for your comment. My objective of this blog is to describe where the Model in an Angular app. I am not talking which is the best approach. A typical answer for the best approach is "it depends". In some mission critical applications you have to keep your business logic on the server while in others you can keep it on the javascript side.

    I agree with you that we should not do layers just for the sake of it. If our application needs it and it is justifiable for the complexity and overhead then we should definitely go for the separation.

    ReplyDelete
  3. Yes, i agree with your point. $scope object cannot be the model. In Angular Model is just a JavaScript object.

    Angularjs Training in Chennai

    ReplyDelete
  4. One of the simplest and the smartest solutions for Angular model.

    ReplyDelete
  5. Very cool and grammotno article, especially how avtror clarifies the meaning of "model" and then demonstrates the clear concept of the script. Very informative and interesting! Thank you for sharing
    Richard Brown virtual data rooms

    ReplyDelete