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
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.
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.
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.
$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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With