Successfully reported this slideshow.

Resources and relationships at front-end



1 of 54
1 of 54

More Related Content

Related Books

Free with a 30 day trial from Scribd

See all

Resources and relationships at front-end

  1. 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: , Twitter: @himkp, Email: This presentation: Download / Fork on GitHub:
  2. 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. 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. 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
  5. 5. Well ok, lets make a Single Page App!
  6. 6. Thus begins our SPA Journey... with Angular.js + Angular UI Router + Require.js
  7. 7. And then, there were...
  8. 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. 9. POJOs as Models? Yes, Plain Old Javascript Objects! Hmm, sounds cool!
  10. 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
  11. 11. The result:
  12. 12. That was easy, but...
  13. 13. A real model, usually... is a rather big and complex object lies on the server
  14. 14. Ok, lets request the server! $http shall answer all our queries
  15. 15. The code... The controller function MyCtrl($scope, $http) { $http.get('/user').success(function (user) { $scope.user = user; }); } The view <h1 ng-controller="MyCtrl"> Hello there, {{}} </h1> The model // HTTP GET { "id": 1234, "name": "John Doe", "email": "" }
  16. 16. The result: Pretty sweet, right?
  17. 17. But hold on... Back in the real world, things aren't so simple.
  18. 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. 19. And while answering the questions, How do you make sure your code is: DRY Consistent Scalable Testable
  20. 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.
  21. 21. This looks like a job for...
  22. 22. $resource
  23. 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. 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, {{}} </h1>
  25. 25. The result: Looks no different from the previous output, but our code is a lot more extendible with the above logic.
  26. 26. The journey continues... Application grows bigger Several views, controllers and resources Editable content
  27. 27. Incoming problems that say...
  28. 28. Which include View inconsistencies Duplicated model functionality The code isn't DRY anymore
  29. 29. Editable content
  30. 30. What is it? Edit a model using a form The model gets updated in that view But not other views across the app Result: inconsistency
  31. 31. Inconsistencies? Multiple views render the same model Each with different values Example: Blog, edit author name, save
  32. 32. Why are inconstencies so bad? Contradicting/misleading information Worse than having no information at all
  33. 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, {{}} </h1>
  34. 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=""> 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.newName; $scope.user.$save(); }; }
  35. 35. The result: Separation of concerns is good, but not if it leads to such an inconsistency.
  36. 36. The solution Maintain references of that model throughout the app When it changes, propagate that change to all instances
  37. 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. 38. The solution: Relationships Relationships to handle sub-resources Maintaining a single reference for each unique resource / sub-resource
  39. 39. Relationships
  40. 40. Parent and children A property on a resource belongs to another resource Example: 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
  41. 41. Subsequent problem Maintaining references
  42. 42. References?
  43. 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.
  44. 44. Looks like a job for...
  45. 45. Transformer A service Input: A backend response object Output: A transformed mesh of resources
  46. 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. 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. 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:, By maintaining an index A key value pair where: Key: the unique identification above Value: the actual resource
  49. 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. 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. 51. Putting it all together Relationships Resource Transformation Indexing / Maintaining References A configurable schema The result: ResourceManager
  52. 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. 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. 54. Thank You Questions / Comments / Suggestions? Reach Out Web: GitHub: @fleon Twitter: @himkp Email: View this presentation: Download / Fork on GitHub: