Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Managing data models in AngularJS the correct way

Tags:

angularjs

As I scour the internet, I am finding so many different ways to manage the data model that is used in our Angular templates, but they all only show a small part of the bigger picture. In a large application we need to glue together API data to some form of JavaScript model which in turn is used within our template, but I am not sure how this should all be managed.

After reading this article on AngularJS models I am now aware that I should be wrapping all of my models in a service so the information is available across multiple controllers. One of the only things is that it does not explain how to tie these Services in with API requests.

Here is my current implementation.

Customer Model

var Customer = function (obj) {
    var self = this;

    if (!obj) {
        self.Name = null;
        self.Address = null;
        self.PrimaryEmailAddress = null;
        self.SecondaryEmailAddress = null;
        self.PhoneNumber = null;

    } else {
        self = obj;
    }

    return self;
}

Then in my controller I use this model on my $scope like

Customer Controller

app.controller('CustomerController', [function($scope, API){
    $scope.model = {};

    API.Account.getCustomer({id:'12345'}, function(data){
        $scope.model = new Customer(data);
    });

}]);

This is what my API service looks like

API Service

app.factory("API", ["$resource", function ($resource) {

    var service = {};

    service.Account = $resource('/WebApi/Account/:type/:id', {},
                        {
                            getCustomer: { method: 'GET', params: { type: 'Customer' } }
                        });

    return service;

}])

This has worked fairly well up until now, when I realized that there is API information that is gathered in a parent controller that is now needed in a child controller

Going back to the article linked above, I now can change my models around so they are wrapped in an Angular Service and are therefore available across multiple controllers. This new CustomerService may look like this

NEW CustomerService

app.factory('CustomerService', function() {
  var CustomerService = {};
  var customer = new Customer();

  CustomerService.getCustomer = function() { return customer; }
  CustomerService.setCustomer = function(obj) { customer = obj; }

  return CustomerService;
});

This isn't quite like the article (much simpler) but it basically contains the OO-like functions to get and set the Customer object.

The problem with this way is we still don't have access to the actual API endpoint to get the customer data from the server? Should we keep the API Service and the Model Services seperate or try to combine them into a single Service? If we do this then we also need a way to differentiate between actually getting fresh data from the server and just getting the currently set Customer object in the singleton object.

I would like to know your initial response to this predicament?

UPDATE

I came across this article that brings together all the functionality of a model including the API requests into a factory service

like image 398
Matt Hintzke Avatar asked Aug 28 '14 00:08

Matt Hintzke


People also ask

Which method is used to create models in AngularJS?

In basic examples, AngularJS uses the $scope object as the model. However, in the previous article I showed how using the controllerAs method allowed the controller itself to be added to the scope with a given name and essentially be used as the model.

Which is the correct syntax of creating AngularJS controller?

The ng-controller="myCtrl" attribute is an AngularJS directive. It defines a controller. The myCtrl function is a JavaScript function. AngularJS will invoke the controller with a $scope object.

What is model in AngularJS?

ng-model is a directive in Angular. JS that represents models and its primary purpose is to bind the “view” to the “model”. For example, suppose you wanted to present a simple page to the end user like the one shown below which asks the user to enter the “First name” and “Last name” in textboxes.

What is $Ctrl in AngularJS?

$ctrl is the view model object in your controller. This $ctrl is a name you choose (vm is another most common name), if you check your code you can see the definition as $ctrl = this; , so basically its the this keyword of the controller function.


1 Answers

Model service and API service should be separate. The API service can depend on model service and return model objects instead of directly returning what came from api.

app.factory("API", ["$resource",'Customer','$q' function ($resource,Customer,$q) {

    var service = {};

    service.Account = function(accountId) {
         var defer=$q.defer();     
         var r=$resource('/WebApi/Account/:type/:id', {},
                        {
                            getCustomer: { method: 'GET', params: { type: 'Customer' }}
                        });
         r.getCustomer({id:'12345'}, function(data){
             defer.resolve(new Customer(data));
         })
         return defer.promise;
     }
     return service;

}]);

This way you have combined the model service and API service. I am assuming Customer is a model service rather than the Customer object.

Update: Based on your follow up question, i thought there could be a better way, but i have not tried it. Rather than creating own promise every time we can use the resource promise:

service.Account = function(accountId) {
         var r=$resource('/WebApi/Account/:type/:id', {},
                        {
                            getCustomer: { method: 'GET', params: { type: 'Customer' }}
                        });
         return r.getCustomer({id:'12345'}).$promise.then(function(data) {
            return new Customer(data); 
         });
}

Since the then method itself returns promise that is resolved to return value of the then callback statement this should work. Try this approach and share your findings

like image 188
Chandermani Avatar answered Oct 12 '22 12:10

Chandermani