Data models in Angular 1 & 2
-
Upload
adam-klein -
Category
Technology
-
view
439 -
download
4
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