54
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: , Email: fleon.org @himkp [email protected] This presentation: Download / Fork on GitHub: http://lab.fleon.org/angularjs-and-resources/ https://github.com/fleon/angularjs-and-resources

Resources and relationships at front-end

Embed Size (px)

DESCRIPTION

This presentation is about effectively managing Resources (Models) and their relationships in your single page application (based on AngularJS)

Citation preview

Page 1: Resources and relationships at front-end

Angular.js and ResourcesEffectively Managing Resources (Models) in Your Angular.js Based Single

Page Applicationby Himanshu Kapoor, Front-end Engineer, Wingify

Web: , Twitter: , Email: fleon.org @himkp [email protected]

This presentation:

Download / Fork on GitHub:

http://lab.fleon.org/angularjs-and-resources/https://github.com/fleon/angularjs-and-resources

Page 2: Resources and relationships at front-end

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.)

Page 3: Resources and relationships at front-end

Why Single Page Apps™?Why should you make Single Page Apps?

They're coolEverybody else is doing itThe ™ symbol on it looks cool

Page 4: Resources and relationships at front-end

Why Single Page Apps™?The real reasons...

Faster experience: no page refresh, on-demand data fetchingBetter runtimes: V8, spidermonkeyHeightened expectations: new products, mobile

Page 5: Resources and relationships at front-end

Well ok, lets make a Single Page App!

Page 6: Resources and relationships at front-end

Thus begins our SPA Journey...with Angular.js + Angular UI Router + Require.js

Page 7: Resources and relationships at front-end

And then, there were...

Page 8: Resources and relationships at front-end

Models, Views and ControllersMVC 101: Angular.js Edition

Views: rendered in the browser

Controllers: makes your view dynamic, has the logic

Models: plain old POJOs

Page 9: Resources and relationships at front-end

POJOs as Models?Yes, Plain Old Javascript Objects!

Hmm, sounds cool!

Page 10: Resources and relationships at front-end

OK, here's what we got...The controller

The view

The model

function MyCtrl($scope) { $scope.myModel = 'hello world';}

<h1 ng-controller="MyCtrl"> {{myModel}}</h1>

// myModel is a POJO model

Page 11: Resources and relationships at front-end

The result:

Page 12: Resources and relationships at front-end

That was easy, but...

Page 13: Resources and relationships at front-end

A real model, usually...is a rather big and complex objectlies on the server

Page 14: Resources and relationships at front-end

Ok, lets request the server!$http shall answer all our queries

Page 15: Resources and relationships at front-end

The code...The controller

The view

The model

function MyCtrl($scope, $http) { $http.get('/user').success(function (user) { $scope.user = user; });}

<h1 ng-controller="MyCtrl"> Hello there, {{user.name}}</h1>

// HTTP GET{ "id": 1234, "name": "John Doe", "email": "[email protected]"}

Page 16: Resources and relationships at front-end

The result:

Pretty sweet, right?

Page 17: Resources and relationships at front-end

But hold on...Back in the real world, things aren't so simple.

Page 18: Resources and relationships at front-end

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?

Page 19: Resources and relationships at front-end

And while answering the questions,How do you make sure your code is:

DRYConsistentScalableTestable

Page 20: Resources and relationships at front-end

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.

Page 21: Resources and relationships at front-end

This looks like a job for...

Page 22: Resources and relationships at front-end

$resource

Page 23: Resources and relationships at front-end

$resource to the rescue!A configurable REST adapterAn abstraction of HTTP methodsAbility to add custom actionsPromise-based APIResources are lazily loaded

Page 24: Resources and relationships at front-end

Time for some code...The model

The controller

The view

app.factory('UserResource', function () { return $resource('/user/:userId', { userId: '@id' });});

function MyCtrl($scope, UserResource) { $scope.user = UserResource.get({ id: 1 });}

<h1 ng-controller="MyCtrl"> Hello there, {{user.name}}</h1>

Page 25: Resources and relationships at front-end

The result:

Looks no different from the previous output,

but our code is a lot more extendible with the above logic.

Page 26: Resources and relationships at front-end

The journey continues...Application grows biggerSeveral views, controllers and resourcesEditable content

Page 27: Resources and relationships at front-end

Incoming problems that say...

Page 28: Resources and relationships at front-end

Which includeView inconsistenciesDuplicated model functionalityThe code isn't DRY anymore

Page 29: Resources and relationships at front-end

Editable content

Page 30: Resources and relationships at front-end

What is it?Edit a model using a formThe model gets updated in that viewBut not other views across the appResult: inconsistency

Page 31: Resources and relationships at front-end

Inconsistencies?Multiple views render the same modelEach with different valuesExample: Blog, edit author name, save

Page 32: Resources and relationships at front-end

Why are inconstencies so bad?Contradicting/misleading informationWorse than having no information at all

Page 33: Resources and relationships at front-end

Here's an example:In addition to the code we already have:

The model

The controller

The view

app.factory('UserResource', function () { return $resource('/user/:userId', { userId: '@id' });});

function MyCtrl($scope, UserResource) { $scope.user = UserResource.get({ id: 1 });}

<h1 ng-controller="MyCtrl"> Hello there, {{user.name}}</h1>

Page 34: Resources and relationships at front-end

Let us add another view that does something else, and something more...

The view

The controller

<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>

function MyEditCtrl($scope, UserResource) { $scope.user = UserResource.get({ id: 1 }); $scope.updateName = function () { $scope.user.name = $scope.newName; $scope.user.$save(); };}

Page 35: Resources and relationships at front-end

The result:

Separation of concerns is good, but not if it leads to such an inconsistency.

Page 36: Resources and relationships at front-end

The solutionMaintain references of that model throughout the appWhen it changes, propagate that change to all instances

Page 37: Resources and relationships at front-end

Real world inconsistencies:Editing a resource that is related to multiple parent resourcesExample: author ~ post, author ~ commentMaintaining references here isn’t so trivial

Page 38: Resources and relationships at front-end

The solution: RelationshipsRelationships to handle sub-resourcesMaintaining a single reference for each unique resource / sub-resource

Page 39: Resources and relationships at front-end

Relationships

Page 40: Resources and relationships at front-end

Parent and childrenA property on a resource belongs to another resourceExample:

post.author is an AuthorResource,

author.posts is a collection of PostResourcesFour kinds of relationships: one-to-one, one-to-many, many-to-one, many-to-many

Page 41: Resources and relationships at front-end

Subsequent problemMaintaining references

Page 42: Resources and relationships at front-end

References?

Page 43: Resources and relationships at front-end

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=1UserResource with id=2PostResource with id=1

Q. How are such references maintained?

A. By transforming each backend response.

Page 44: Resources and relationships at front-end

Looks like a job for...

Page 45: Resources and relationships at front-end

TransformerA serviceInput: A backend response objectOutput: A transformed mesh of resources

Page 46: Resources and relationships at front-end

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"}]

Page 47: Resources and relationships at front-end

The output:// Output obtained by transforming the response abovevar 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);

Page 48: Resources and relationships at front-end

How would such a transformation bepossible?

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

Page 49: Resources and relationships at front-end

Scalablity by abstractionSolving the same problem for different resources across the appIndexing each resource instance by a given propertyTransforming relationships between parents and children recursively

How?

Abstract out the core logic from configurable inputIn this particular case: the configuration is a schema

Page 50: Resources and relationships at front-end

The End ResultAn abstracted base that every resource stands on that is:

ScalableTestableConfigurable

Prevention of mixing resource management logic with the business logic

The core logic stays at a single place

Page 51: Resources and relationships at front-end

Putting it all togetherRelationshipsResource TransformationIndexing / Maintaining ReferencesA configurable schema

The result: ResourceManager

Page 52: Resources and relationships at front-end

Resource ManagerAn abstraction of resource-related problems faced while developing VWOA lot of them described in this presentationWe will be open-sourcing it soon

Page 53: Resources and relationships at front-end

General LearningsAbstract out duplicate logicAbstract out configurations from the logicThink recursivelyResearch along each stepTake inspiration from other libraries (In this particular case, it was Ember-Data)

Page 54: Resources and relationships at front-end

Thank YouQuestions / Comments / Suggestions?Reach Out

Web: fleon.orgGitHub: @fleonTwitter: @himkpEmail: [email protected]

View this presentation: Download / Fork on GitHub:

http://lab.fleon.org/angularjs-and-resources/http://github.com/fleon/angularjs-and-

resources/