1. Angular.js and Resources
Effectively Managing Resources (Models) in Your Angular.js Based Single
Page Application
by Himanshu Kapoor, Front-end Engineer, Wingify
Web: , fleon.org Twitter: @himkp, Email: info@fleon.org
This presentation:
http://lab.fleon.org/angularjs-and-resources/
https://github.com/fleon/angularjs-and-resources
Download / Fork on GitHub:
2. The interwebs today...
Single Page Apps™
(Today's Hot Topic)
+
Front-end Frameworks
(Our Pick: Angular.js)
+
Moar Stuff
(Package Management, AMD, Project Organisation, etc.)
3. Why Single Page Apps™?
Why should you make Single Page Apps?
They're cool
Everybody else is doing it
The ™ symbol on it looks cool
4. Why Single Page Apps™?
The real reasons...
Faster experience: no page refresh, on-demand data fetching
Better runtimes: V8, spidermonkey
Heightened expectations: new products, mobile
8. Models, Views and Controllers
MVC 101: Angular.js Edition
Views: rendered in the browser
Controllers: makes your view dynamic, has the logic
Models: plain old POJOs
9. POJOs as Models?
Yes, Plain Old Javascript Objects!
Hmm, sounds cool!
10. OK, here's what we got...
The controller
function MyCtrl($scope) {
$scope.myModel = 'hello world';
}
The view
<h1 ng-controller="MyCtrl">
{{myModel}}
</h1>
The model
// myModel is a POJO model
17. But hold on...
Back in the real world, things aren't so simple.
18. The problems:
What about multiple views?
What about other kinds of actions (POST, PATCH, PUT, DELETE)?
What about muliple types of models (users, posts, comments)?
How do you handle multiple instances of the same model?
19. And while answering the questions,
How do you make sure your code is:
DRY
Consistent
Scalable
Testable
20. And here are the answers...
Q: What about multiple views?
A: Abstract out the model in a service.
Q: What about other kinds of actions?
A: Add support for those methods in the service.
Q: What about muliple types of models?
A: Add support for instantiating different model types in the service.
23. $resource to the rescue!
A configurable REST adapter
An abstraction of HTTP methods
Ability to add custom actions
Promise-based API
Resources are lazily loaded
24. Time for some code...
The model
app.factory('UserResource', function () {
return $resource('/user/:userId', {
userId: '@id'
});
});
The controller
function MyCtrl($scope, UserResource) {
$scope.user = UserResource.get({
id: 1
});
}
The view
<h1 ng-controller="MyCtrl">
Hello there, {{user.name}}
</h1>
25. The result:
Looks no different from the previous output,
but our code is a lot more extendible with the above logic.
26. The journey continues...
Application grows bigger
Several views, controllers and resources
Editable content
32. Why are inconstencies so bad?
Contradicting/misleading information
Worse than having no information at all
33. Here's an example:
In addition to the code we already have:
The model
app.factory('UserResource', function () {
return $resource('/user/:userId', {
userId: '@id'
});
});
The controller
function MyCtrl($scope, UserResource) {
$scope.user = UserResource.get({
id: 1
});
}
The view
<h1 ng-controller="MyCtrl">
Hello there, {{user.name}}
</h1>
34. Let us add another view that does something else, and something more...
The view
<hr>
<h2>Edit your name</h2>
<form ng-controller="MyEditCtrl" ng-if="user.name">
New name: <input type="text" ng-model="newName">
<button ng-click="updateName()">Save</button>
</form>
The controller
function MyEditCtrl($scope, UserResource) {
$scope.user = UserResource.get({
id: 1
});
$scope.updateName = function () {
$scope.user.name = $scope.newName;
$scope.user.$save();
};
}
35. The result:
Separation of concerns is good, but not if it leads to such an inconsistency.
36. The solution
Maintain references of that model throughout the app
When it changes, propagate that change to all instances
37. Real world inconsistencies:
Editing a resource that is related to multiple parent resources
Example: author ~ post, author ~ comment
Maintaining references here isn’t so trivial
38. The solution: Relationships
Relationships to handle sub-resources
Maintaining a single reference for each unique resource / sub-resource
40. Parent and children
A property on a resource belongs to another resource
Example:
post.author is an AuthorResource,
author.posts is a collection of PostResources
Four kinds of relationships: one-to-one, one-to-many, many-to-one, many-to-
many
43. What are references?
Maintaining references: Ensuring that each unique resource has only one
instance throughout the app.
For instance, there should be only one instance of:
UserResource with id=1
UserResource with id=2
PostResource with id=1
Q. How are such references maintained?
A. By transforming each backend response.
45. Transformer
A service
Input: A backend response object
Output: A transformed mesh of resources
46. Example input:
// GET /posts
[{
"id": 1,
"createdBy": { "id": 1, "name": "John Doe" }
"title": "My First Post",
"excerpt": "Lorem Ipsum"
}, {
"id": 2,
"createdBy": { "id": 1, "name": "John Doe" }
"title": "My Second Post",
"excerpt": "Lorem Ipsum"
}, {
"id": 3,
"createdBy": { "id": 1, "name": "Jony Ive" }
"title": "My Third Post",
"excerpt": "Lorem Ipsum"
}]
47. The output:
// Output obtained by transforming the response above
var output = /* ... */;
expect(output).toEqual(any(Array));
expect(output.length).toBe(3);
expect(output[0]).toEqual(any(PostResource))
expect(output[1]).toEqual(any(PostResource))
expect(output[2]).toEqual(any(PostResource))
expect(output[0].createdBy).toBe(output[1].createdBy);
expect(output[0].createdBy).toBe(output[2].createdBy);
48. How would such a transformation be
possible?
By identifying unique resources
By getting one or more properties that can uniquely identify a resource
For example: post.id, author.id
By maintaining an index
A key value pair where:
Key: the unique identification above
Value: the actual resource
49. Scalablity by abstraction
Solving the same problem for different resources across the app
Indexing each resource instance by a given property
Transforming relationships between parents and children recursively
How?
Abstract out the core logic from configurable input
In this particular case: the configuration is a schema
50. The End Result
An abstracted base that every resource stands on that is:
Scalable
Testable
Configurable
Prevention of mixing resource management logic with the business logic
The core logic stays at a single place
51. Putting it all together
Relationships
Resource Transformation
Indexing / Maintaining References
A configurable schema
The result: ResourceManager
52. Resource Manager
An abstraction of resource-related problems faced while developing VWO
A lot of them described in this presentation
We will be open-sourcing it soon
53. General Learnings
Abstract out duplicate logic
Abstract out configurations from the logic
Think recursively
Research along each step
Take inspiration from other libraries
(In this particular case, it was Ember-Data)
54. Thank You
Questions / Comments / Suggestions?
Reach Out
Web: fleon.org
GitHub: @fleon
Twitter: @himkp
Email: info@fleon.org
View this presentation:
Download / Fork on GitHub:
http://lab.fleon.org/angularjs-and-resources/
http://github.com/fleon/angularjs-and-resources/