KEMBAR78
Data models in Angular 1 & 2 | PDF
Data Models inData Models in
Angular 1 & 2Angular 1 & 2
Adam Klein
CTO @ 500Tech
UsUs
AngularJS consulting, development, team building
AngularJS-IL Community on meetup.com
helped with ng-conf
Pssst....
AngularJS Course - 20.5
We're looking for experienced
NodeJS developers
AngularJS developers
Data models in AngularData models in Angular
There's no such thing
Angular focuses on VC
You have a service - do whatever
you want with it
?
What's the big deal?What's the big deal?
Unreliable Data
partial
incomplete
stale
Live in a browser
your app keeps restarting
it might be opened in
parallel
it has limited resources
JSON server
sync & async mixed
flakiness
no standard
Angular
bindable
Data Access != Network AccessData Access != Network Access
Network Layer
routes & parameters
RESTFul APIs
interceptors
http headers
Web Sockets
Data Access Layer (DAL)
data transformation
persisting
caching
access methods
aggregation
Existing solutionsExisting solutions
NetworkNetwork
$http
$resource
RestangularOther
libraries
$resource$resource
1 file, 661 lines of code
built-in to angular
Network:
RESTFul routes
Path & Params building
Interceptors
Data:
Prototypes
Bindable to template
RestangularRestangular
A better version of $resource
5794 stars on github
1 file with 1351 lines of code
Maintained by one Argentian guy
A bit more complex and
configurable
Doesn't matterDoesn't matter
Just wrap it in a serviceJust wrap it in a service
Data AccessData Access
A.K.A.A.K.A.
DALDAL
DAODAO
ModelModel
DataServiceDataService
Breeze
JS-data-angular
Backbone
Model
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 of
datadata
Controller is in charge ofController is in charge of
view stateview state
BetterBetter
class 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;
});
}
}
OOPOOP
class Todo {
constructor() {
this.completed = false;
}
totalTime() {
return this.completedAt - this.startedAt;
}
}
Working 'offline'Working 'offline'
Don't wait for server
Better UX
when user owns data
editors
Don't allow inputting wrong data
Indications to user
Synchronisation 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 on
the wallthe wall
Bindable to scopeBindable to scope
Controller:
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 DAO
Use 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 Smell
class DataService {
constructor($state, $modal, $rootScope) {
}
}
CachingCaching
class BeerBottlesService {
query() {
return this.$http('beer_bottles');
}
}
CachingCaching
constructor() {
this._beerBottles = null;
}
query() {
if (this._beerBottles) {
return this._beerBottles;
}
else {
return this.$http('beer_bottles')
.then((bottles) => {
return this._beerBottles = bottles;
});
}
}
CachingCaching
constructor() {
this._beerBottles = null;
}
query() {
if (!this._beerBottles) {
this._beerBottles = this.$http('beer_bottles');
}
return this._beerBottles;
}
Cache the promise, not the data
ParameterisedParameterised
cachingcaching
Maintain a hash of promises
{
1: Promise that object 1 will return
2: Promise that object 2 will return
...
}
Http CacheHttp Cache
Sometimes is good enough
URL 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-angular
Jason Dobry
js-data - 454 stars
js-data-angular - 932 stars
December 2013
started for angular, inspired by ember-
data
https://www.youtube.com/watch?
v=8wxnnJA9FKw
js-data-angularjs-data-angular
bind to controller
identity maps
query language
sync & async
computed properties
prototyping and static methods
totally configurable
change detection
validations
cache 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/1DM
acL7iwjSMPP0ytZfugpU4v0PWUK0BT6lhya
VEmlBQ/edit
https://docs.google.com/document/d/1US
9h0ORqBltl71TlEU6s76ix8SUnOLE2jabHVg
9xxEA/edit#heading=h.oisbys59gdxa
What's been doneWhat's been done
A lot of research
Collaboration with other teams
GoalsGoals
No Boilerplate
BYOData
Working with existing libraries authors
Don't dictate behaviour
Don't dictate server integration
Recognise different flows
In other words - a fantasy?
Future of webFuture of web
collaborationcollaboration
realtime datarealtime data
offline workoffline work
PhasesPhases
1. Utilities
2. Offline
3. Rich data
More considerationsMore considerations
1. Security
2. Bindability
3. Performance
4. Storage limitations
5. Mocking & Testability
Structured FormsStructured Forms
Bindable realtime dataBindable realtime data
using observables and async pipes
// Component
this.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 a
watwat
"We want to make API more"We want to make API more
intuitive"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 you
Adam Klein
500Tech.com
meetup.com/angularjs-il
hackademy.co.il
github.com/adamkleingit
https://twitter.com/500techil

Data models in Angular 1 & 2