Data models in Angular 1 & 2

Post on 13-Apr-2017

438 views 4 download

Transcript of Data models in Angular 1 & 2

Data Models inData Models inAngular 1 & 2Angular 1 & 2Adam KleinCTO @ 500Tech

UsUsAngularJS consulting, development, team buildingAngularJS-IL Community on meetup.comhelped with ng-conf Pssst.... AngularJS Course - 20.5We're looking for experienced

NodeJS developersAngularJS developers

Data models in AngularData models in AngularThere's no such thingAngular focuses on VCYou have a service - do whateveryou want with it

?

What's the big deal?What's the big deal?Unreliable Data

partialincomplete stale

Live in a browser

your app keeps restartingit might be opened inparallelit has limited resources

JSON server

sync & async mixed flakinessno standard

Angular

bindable

Data Access != Network AccessData Access != Network Access

Network Layer

routes & parametersRESTFul APIsinterceptorshttp headersWeb Sockets

Data Access Layer (DAL)

data transformationpersistingcachingaccess methodsaggregation

Existing solutionsExisting solutions

NetworkNetwork

$http$resource

RestangularOtherlibraries

$resource$resource1 file, 661 lines of codebuilt-in to angularNetwork:

RESTFul routesPath & Params buildingInterceptors

Data:PrototypesBindable to template

RestangularRestangularA better version of $resource5794 stars on github1 file with 1351 lines of codeMaintained by one Argentian guyA bit more complex andconfigurable

Doesn't matterDoesn't matterJust wrap it in a serviceJust wrap it in a service

Data AccessData AccessA.K.A.A.K.A.DALDALDAODAO

ModelModelDataServiceDataService

BreezeJS-data-angular

BackboneModel

Your own

Ember Data

Todo MVCTodo MVC

Who owns the data?Who owns the data?class TodoController { createTodo(todo) { todo.completed = false; this.TodoService.post(todo).then((todo) => { this.todos.push(todo); }); }}

class TodoService { post(todo) { return this.$http.post('/todos', todo); }}

DAO is in charge ofDAO is in charge ofdatadata

Controller is in charge ofController is in charge ofview stateview state

BetterBetterclass TodoController { createTodo(todo) { this.saving = true; this.TodoService.add(todo).then(() => { this.saving = false; }); }}

class TodoService { add(todo) { todo.completed = false; return this.$http.post('/todos', todo) .then((todo) => { this.todos.push(todo)); return todo; }); }}

OOPOOPclass Todo { constructor() { this.completed = false; } totalTime() { return this.completedAt - this.startedAt; }}

Working 'offline'Working 'offline'

Don't wait for serverBetter UXwhen user owns data editors

Don't allow inputting wrong dataIndications to userSynchronisation problems

Working offlineWorking offline

class TodoStore { create(todo) { this.todos.push(todo); return $http.post('/todos', todo); }}

99 bottles of beer on99 bottles of beer onthe wallthe wall

Bindable to scopeBindable to scopeController: this.beerBottles = DataService.beerBottles; $interval(() => { DataService.query(); }, 2000);

DataService:

this.beerBottles = []; query() { return this.$http.get('/beer_bottles') .then((bottles) => this.beerBottles = bottles); }

Possible solution?Possible solution?Controller: this.data = DataService; $interval(() => { DataService.query(); }, 2000);

Template:<div> {{ Ctrl.data.items.length }} bottles of beer on the wall,<br> {{ Ctrl.data.items.length }} bottles of beer<br> if one of the bottles should happen to fall....<br><br> {{ Ctrl.data.items.length - 1 }} bottles of beer on the wall!</div>

Don't couple view with DAODon't couple view with DAOUse angular.copy

constructor() { this._beerBottlesData = []; } query() { return this.$http('beer_bottles') .then((bottles) => { angular.copy(bottles, this._beerBottlesData); return this._beerBottlesData; }); }

getList() { return this._beerBottlesData; }

Code SmellCode Smellclass DataService { constructor($state, $modal, $rootScope) { }}

CachingCachingclass BeerBottlesService { query() { return this.$http('beer_bottles'); }}

CachingCachingconstructor() { this._beerBottles = null;}query() { if (this._beerBottles) { return this._beerBottles; } else { return this.$http('beer_bottles') .then((bottles) => { return this._beerBottles = bottles; }); }}

CachingCachingconstructor() { this._beerBottles = null;}

query() { if (!this._beerBottles) { this._beerBottles = this.$http('beer_bottles'); } return this._beerBottles;}

Cache the promise, not the data

ParameterisedParameterisedcachingcaching

Maintain a hash of promises{ 1: Promise that object 1 will return 2: Promise that object 2 will return ...}

Http CacheHttp CacheSometimes is good enoughURL based, not resource based

TreesTrees

JSON editorJSON editor{ config: { baseUrl: 'http://my.website.com', port: 3000, allowedMethods: ['POST', 'GET'], resources: { users: {access: 'admin'}, posts: {access: 'user'}, pages: {access: 'guest'} } }}

{ name: 'config', type: 'Object', children: [ { name: 'baseUrl', type: 'String', value: 'http://my.website.com' }, { name: 'port', type: 'Integer', value: 3000 }, { name: 'allowedMethods', type: 'Array', value: ['POST', 'GET', 'DELETE'] }, { name: 'resources', type: 'Object', children: [ ... ] } ]}

Same data, different representationsSame data, different representations

js-data-angularjs-data-angularJason Dobry

js-data - 454 starsjs-data-angular - 932 starsDecember 2013started for angular, inspired by ember-data

https://www.youtube.com/watch?v=8wxnnJA9FKw

js-data-angularjs-data-angularbind to controller

identity mapsquery language

sync & asynccomputed properties

prototyping and static methodstotally configurablechange detection

validationscache expiration

framework agnostic (even runs on node)

Angular 2.0Angular 2.0

https://www.youtube.com/watch?v=Bm3eDgZZMFs

https://docs.google.com/document/d/1DMacL7iwjSMPP0ytZfugpU4v0PWUK0BT6lhya

VEmlBQ/edit

https://docs.google.com/document/d/1US9h0ORqBltl71TlEU6s76ix8SUnOLE2jabHVg

9xxEA/edit#heading=h.oisbys59gdxa

What's been doneWhat's been doneA lot of researchCollaboration with other teams

GoalsGoalsNo BoilerplateBYODataWorking with existing libraries authorsDon't dictate behaviourDon't dictate server integrationRecognise different flowsIn other words - a fantasy?

Future of webFuture of webcollaborationcollaboration

realtime datarealtime data

offline workoffline work

PhasesPhases1. Utilities2. Offline3. Rich data

More considerationsMore considerations1. Security2. Bindability3. Performance4. Storage limitations5. Mocking & Testability

Structured FormsStructured Forms

Bindable realtime dataBindable realtime datausing observables and async pipes

// Componentthis.count = http('http://beer.factory/bottles'). map((bottles) => bottles.length)

// Template<span> {{ count | async }} bottles of beer on the wall</span>

Let's finish with aLet's finish with awatwat

"We want to make API more"We want to make API moreintuitive"intuitive"

How you do http short polling

var beerBottles = Rx.Observable.interval(60 * 2000). map(() => 'http://beerfactory.com/api/beer_bottles'). flatMapLatest(http). subscribe()

Thank youThank youAdam Klein500Tech.commeetup.com/angularjs-ilhackademy.co.ilgithub.com/adamkleingithttps://twitter.com/500techil