This post is a continuation of AngularJS: a retrospective
We were tasked with creating a web application that was being developed simultaneously with an API from another team. Our AngularJS thick client web application had to be able to respond quickly to changes in business requirements, and changes in the API. Our priority of separating concerns and keeping single sources of truth served us well. We started by defining our own base data model class, which we called PropertyModel.
PropertyModel, our base data model class
We wanted a standard interface for accessing both properties (
object.property) and methods (
object.method()). When we consume data, we don't want to worry about it's implementation. What we came up with is the PropertyModel. With a consistent interface, we didn't have to hunt down which parts of code requested a value that was once a simple property accessor is now a full blown method.
PropertyModel stores key value pairs on
@properties, and accesses them with
Because we're accessing via a method, we can redirect calls with an appropriate method in
@accessors prefixed with either
It doesn't matter if it's a plain old property or a method; it will be accessed as `model.get('propName').
User model with accessor methods
get_fullName is an example composite property. There is no
get_gender is an example of intercepting a value lookup. Imagine that
@properties.gender is normally present, but for some of our earlier users we forgot to ask for it. Here, we can make an educated guess based on
get_isTaxable is an example logic check for a business requirement. Perhaps your app needs to apply sales tax based on where the user lives. By having this check on the user model, when your requirements change, you can update the single source of truth. Note: Server side validation of user data is always necessary.
Our services were responsible for all API calls. After a successful API call, a service creates a new user with the appropriate factory. For a failed call, the service logs the error to the console, then carries on the
promise rejection with
$q.reject without which the callee would not receive the error. When the API is updated the service may be the only part of your application that needs updating. How about that!
Retrieving the user from a controller
The controller only calls the service with the user ID it wants.