Angular 1.5 and Beyond
FRP ideas meet real life apps


Angular is changing


Nadav Sinai

The React revolution (~2013)
- Functional view of UI via composable components
- Self-contained - HTML (JSX), JS, Css. - Modules.
- NPM eco system, bundler (Webpack) build, Babel etc.
- No dirty checking - programatic state/view sync - of the whole system - but actualy DOM rendering is done after virtual DOM diff. - only changed nodes updated - slow DOM side effects postponed to the boundary of the system
- Encourages one way data flow, very predictable components
- introduced FLUX State Management - very structured
- Adopts ES6 standards, & new JS trends like immutability

Angular 2
Angular 2 is a very different framework to angular 1.5
- Components
- Multi-thredding
- Offline Compilation (server, pre-render etc)
- Modular - NPM ecosystem, build via bundler, CLI tools
- Types (via typescript/dart) in DI
- Bare template API (no ng-xxxx directives to learn)
- Immutability and Observable streams in core

What can we do with Angular 1.x Apps?





- keep things as they are...
- Implement new thinking with old tools
- migrate to new thinking and new tools - step by step
- build completely new apps


Start with the tools...
Angular 1.5 - new features

.component method
Helper to write code by convention and best practices
- cuts down on boilerplate
- provides sane defaults
- allows stateless components
- looks more like angular 2
Angular 1.4
.directive('counter', function counter() {
return {
scope: {},
bindToController: {
count: '='
},
controller: function () {
function increment() {
this.count++;
}
function decrement() {
this.count--;
}
this.increment = increment;
this.decrement = decrement;
},
controllerAs: 'counter',
template: [
'<div class="todo">',
'<input type="text" ng-model="counter.count">',
'<button type="button" ng-click="counter.decrement();">-</button>',
'<button type="button" ng-click="counter.increment();">+</button>',
'</div>'
].join('')
};
});
Angular 1.5
.component('counter', {
template: [
'<div class="todo">',
'<input type="text" ng-model="$ctrl.count">',
'<button type="button" ng-click="$ctrl.decrement();">-</button>',
'<button type="button" ng-click="$ctrl.increment();">+</button>',
'</div>'
].join(''),
bindings: {
count: '='
},
controller: class Counter {
constructor(//DI here//){
this.count = 0;
}
increment() {
this.count++;
}
decrement() {
this.count--;
}
}
});
Template as a function
.component('counter', {
template: ($element,$attr) {
//do your logic
return [
'<div class="todo">',
'<input type="text" ng-model="$ctrl.count">',
'<button type="button" ng-click="$ctrl.decrement();">-</button>',
'<button type="button" ng-click="$ctrl.increment();">+</button>',
'</div>'
].join('');
},
bindings: {
count: '='
},
controller: class Counter {
constructor(){
this.count = 0;
}
increment() {
this.count++;
}
decrement() {
this.count--;
}
}
});
Angular 2.0
@Component({
template: [
'<div class="todo">',
'<input type="text" #count='' ngControl='count' [(ngModel)]="count">',
'<button type="button" (click)="decrement();">-</button>',
'<button type="button" (click)="increment();">+</button>',
'</div>'
].join('');
})
class Counter {
@Input()
public count:number=0;
increment() {
this.count++;
}
decrement() {
this.count--;
}
}
});

In Angular 2 -
Projection is the new transclution
In Angular 1.5
- components have transclusion enabled by default
- it possible to use multi-transclusion slots
Transclusion as a source of data
//html
<multislot-card>
<card-title>Leonard Cohen</card-title>
<card-song>Like a Bird on a wire</card-song>
</multislot-card>
//
//js
angular
.module('app')
.directive('multislotCard', multipleTransclusion);
function multipleTransclusion(){
return {
restrict: 'E',
transclude: {
'title': '?cardTitle',
'song': '?cardSong',
},
template:
'<div>' +
'<h3 ng-transclude="title">No title</h3>' +
'<i ng-transclude="song">Empty</i>' +
'</div>'
};
}
Require and $onInit
Require is used to get other controllers instantiated on same or parent nodes
Angular 1.4
angular
.module('app', [])
.directive('parentComponent', function () {
scope: {},
require: ['^parentDirective', 'ngModel'],
controller: function () {
// controller logic
}
link: function ($scope, $element, $attrs, $ctrl) {
// $ctrl[0] === ^parentDirective
// $ctrl[1] === ^ngModel
},
template: `
<div>
Component: {{ $ctrl.state }}
</div>
`
});
Require and $onInit
We can now use an object
angular
.module('app', [])
.directive('parentComponent', function () {
scope: {},
require: {
ngModelCtrl: 'ngModel'
},
controller: function () {
this.ngModelCtrl.... /// created for us
}
template: `
<div>
Component: {{ $ctrl.state }}
</div>
`
});
Require and $onInit
angular
.module('app', [])
.directive('parentComponent', function () {
scope: {},
require: {
ngModelCtrl: 'ngModel'
},
controller: function () {
this.ngModelCtrl.formatter.push(...) // runtime error!
}
template: `
<div>
Component: {{ $ctrl.state }}
</div>
`
});
Require and $onInit
But parents are instantiated after children,
and order & priority is not known to controller
angular
.module('app', [])
.directive('parentComponent', function () {
scope: {},
require: {
ngModelCtrl: 'ngModel'
},
controller: class ParentComponent() {
$onInit(){
this.ngModelCtrl.formatter.push(...)// do your thing
}
});
One way Data binding
angular
.module('app', [])
.component('example', {
bindings: {
obj: '<',
prim: '<'
},
template: `
<div class="section">
<h4>
Isolate Component
</h4>
<p>Object: {{ $ctrl.obj }}</p>
<p>Primitive: {{ $ctrl.prim }}</p>
<a href="" ng-click="$ctrl.updateValues();">
Change Isolate Values
</a>
</div>
`,
controller: function () {
this.updateValues = function () {
this.prim = 10;
this.obj = {
john: {
age: 35,
location: 'Unknown'
}
};
};
}
};
)})
angular
.module('app')
.controller('ParentController', function ParentController() {
this.somePrimitive = 99;
this.someObject = {
todd: {
age: 25,
location: 'England, UK'
}
};
this.updateValues = function () {
this.somePrimitive = 33;
this.someObject = {
jilles: {
age: 20,
location: 'Netherlands'
}
};
};
}
);
Stateless component
// usage: <name-component></name-component>
angular.module('app).component('nameComponent',{
bindings: {
name: '=',
age: '='
},
template: `
<div>,
<p>Name: {{$ctrl.name}}</p>
<p>Age: {{$ctrl.age}}</p>
</div>`
});
Types of Components
Presetational - components
(dumb component)

Types of Components
Business -
Stateful
(smart components)

Types of Components
View Routing -
(average guy which by chance has the control)

Presentation components
-
Display the user interface
-
Stateless (dumb / pure)
-
Data arrives via bindings (inputs)
-
Data leaves via events (outputs)

Business Components
-
Access services & state
-
Stateful (smart / impure / container)
-
Do not provide interactive user interface
-
Render other Components

View Components
-
Build the current view (from a URL)
-
Specialist (smart/router) components
-
Create components dynamically (via a Router)
-
Can be entry points to the application


More on LifeCycle hooks
- allow us to work without $scope
- provide a similar environment to angular 2
- $onInit()
- $onDestroy()
- $postLink()
- $onChanges(changes)
$onChanges
myVillain.prototype = {
$onChanges: function(changes) {
if (changes.villain) {
this.fullName = getFullName(this.villain);
}
},
...
};
Testing Components

More new stuff with 1.5
- Lazy transclusion
- ng-animate-swap
- $resolve in ng-route
- cancelable requests in ng-resource

Ng-animate-swap
Angular 2 preperation
- Implement new features as components
- move to Typescript
- use NG-FORWARD/NG-UPGRADE
- learn to use Observable streams
- Learn FRP thinking
- learn to use Immutability

- A superset of ES6, compiles to ES 6/5/3
- Allows optional & gradual typing
- Interfaces,Enums, Privacy ....
- Developer oriented - no runtime
- Allows Amazing IDE environment & tools
- Type Metadata used by Angular 2.0 DI

- A Helper module to make the syntax even closer to angular Does not require angular 2
- works with decorators (typescript or babel)

- Use ng 1.x and ng2 togethers
- Injectors are bridged
- Components and directives can be mixed


Observables

Push vs Pull
Observables are lazy Push collections of multiple values. They fill the missing spot in the following table:
Single | Multiple | |
Pull | Function | Iterator/generator |
Push | Promise/callback | ??? |
Push vs Pull
Observables are lazy Push collections of multiple values. They fill the missing spot in the following table:
Single | Multiple | |
Pull | Function | Iterator/generator |
Push | Promise/callback | Observable |
Data streams


Observable spec.
var observable = Rx.Observable.create(function (observer) {
observer.onNext(42);
observer.onCompleted();
return function(){
//do your cleanup stuff here
}
});
var subscription = observable.subscribe(
function (value) {
console.log('Next: %s.', value);
},
function (ev) {
console.log('Error: %s!', ev);
},
function () {
console.log('Completed!');
}
);
subscription.dispose();

RxJs - Reactive Extensions to Javascript
Reactive data streams
Angular and Observables (rx-angular)
observeOnScope($scope, 'search')
.throttle(1000)
.map(function(change){
return change.newValue || "";
})
.distinctUntilChanged()
.flatMapLatest(searchWikipedia)
.safeApply($scope, function(result) {
$scope.data = result;
})
.subscribe();
Angular and Observables (rx-angular)
function searchWikipedia(term) {
return rx.Observable.fromPromise($http({
url: "http://en.wikipedia.org/w/api.php?&callback=JSON_CALLBACK",
method: "jsonp",
params: {
action: "opensearch",
search: encodeURI(term),
format: "json"
}
})
);
}
Programming going FRP


// OOP
let c = new Calculator(0);
// one needs to learn API.
c.add(3);
/// keeping internal state
let result = c.value();
c.subtract(2);
let nextResult = let result = c.value();
///FRP (Functional only really here)
function add(a,b){
return a+ b;
}
let result = add(0,3);
let nextResult = add(result,-2);
//is also polymorphic
let floaty = add(5.56,15.7);
// and even
let together = add('this',' and that');
///Function Rules (laws)
// associative
add(add(1, 2), 4) == add(1, add(2, 4))
// commutative
add(4, 1) == add(1, 4)
// identity
add(n, 0) == n
// distributive
multiply(2, add(3,4)) == add(multiply(2, 3), multiply(2, 4))
///Functional Rules (laws)
//composable
var reverseCap = compose(capitalize, reverse);
reverseCap(“hello”) //=> “Olleh” Composition
//associativity also works in functions
compose(compose(f, g), h) == compose(f, compose(g, h)) Composition (associativity)
/// also for larger scale
var getFromDb = compose(pluck('rows'), User.findAll);
var cleanUpData = compose(capitalize, pluck('name'));
var renderTemplate = TemplateEngine.render(‘users_table');
var makePage = compose(renderTemplate, map(cleanUpData), getFromDb);
makePage({limit: 20}) makePage({limit: 20})
Function Purity
A function is pure when:
- it always gives the same o/p for one i/p
- it has no side effects
- never relies on external state

Pure Functions
Purity makes function
-
Reliable
-
Testable
-
Portable
-
Memoizable
-
Parallelizable
Immutability

Mutability creates probelms
function impureAdd1(val){
myArray.push(val);
}
function impureAdd2(val,myArray){
myArray.push(val);
}
function pureAdd(val,myArray){
return [...myArray,val];
}
JS Data
Mutable | Immutable |
---|---|
Object | String |
Array | Number |
Map/Set | Boolean |
We can keep native
function immutableSplice(arr, start, deleteCount, ...items) {
return [ ...arr.slice(0, start), ...items, ...arr.slice(start + deleteCount) ]
}
function immutableReverse(arr) {
return [ ...arr ].reverse()
}

Facebook Lib (2014)
- Immutable Collections
- Angular integration
- Deep optimizations (TRIE Hashing)
- Great docs
- Angular 1.5
- Angular 1.5 at Angular connect 2015
https://www.youtube.com/watch?v=uXvNDcnLnwU - ng Conf 2016 - angular 1.5
https://www.youtube.com/watch?v=AMwjDibFxno - https://toddmotto.com/exploring-the-angular-1-5-component-method/
- https://toddmotto.com/one-way-data-binding-in-angular-1-5/
- http://httpjunkie.com/2016/1304/angular-1-5-components-docs-and-info/
- Functional Reactive in Ng-conf 2016
-
- RXJS
- Introduction to RXjs
- http://reactivex.io/rxjs/manual/overview.html
- http://rxmarbles.com/
- https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
- RXjs In Depth - https://www.youtube.com/watch?v=KOOT7BArVHQ
- Immutable
- http://facebook.github.io/immutable-js/
- immutability-in-angularjs
Links
Thanks

Angular 1.5 &Beyond
By Nadav SInai
Angular 1.5 &Beyond
Review of how to keep AngularJS app up to date in 2016
- 2,035