Post on 10-Aug-2015
COMPONENTSA N G U L A R +
Shawn McKay@Sh_McK
me@shmck.com
TODAYCOMPONENT ARCHITECTURE,WEB COMPONENTS,ANGULAR 2 COMPONENTS,THE NEW ANGULAR COMPONENT-ROUTER
WHAT’S A COMPONENT?
COMPONENT = MVC
COMPONENTS = LEGO
COMPONENTS = TREES
THEN WHAT’S A WEB COMPONENT?
CUSTOM ELEMENTS
HTML IMPORTS
<TEMPLATE>
SHADOW DOM
DEVELOPERS VS. DESIGNERS
“SOMEBODY’S PROBABLY ALREADY MADE AN ANGULAR LIBRARY FOR THAT”
- LAZY/SMART DEVELOPER
“SOMEBODY’S PROBABLY ALREADY MADE A JQUERY LIBRARY FOR THAT”
- LAZY/SMART DESIGNER
WHY NOT JQUERY EVERYTHING?
WEB COMPONENTS
• Re-usable
• Portable
• Consumable
• Consistent
• Maintainable
• Encapsulated
• Quick to use
• Self-describing
• Just drop it on the page and it works!
• Not framework specific
“SOMEBODY’S PROBABLY ALREADY MADE A WEB COMPONENT FOR THAT”- LAZY DEVELOPER/DESIGNER, EVERYONE AND HIS/HER GRANDMA
WEB COMPONENTS ARE TOO EASY
ANGULAR COMPONENTS
COMPONENT = MVC
1.X: DIRECTIVES
.directive('hiGreeter', hiGreeter);
function hiGreeter() { return { template: '<h1>Hello, {{hi.place}}</h1>', controllerAs: 'hi', controller: function () { this.place = "world" } };}
function hiGreeter() { return { priority: 0, terminal: false, template: '<h1>Hello</h1>', controller: 'MyCtrl', controllerAs: 'MyCtrl', bindToController: true, templateNamespace: 'html', transclude: true, replace: false, multiElement: false, restrict: 'A', require: '^parentCtrl', scope: {
item: '@', tool: '=', func: '?&' }, compile: function (el) { return { pre: function(scope, el, attrs) {}, post: function(scope, el, attrs) {} } }};}
1.X: DIRECTIVE DEFINITION OBJECT
EVERYTHING IN ANGULAR 1.X IS A DIRECTIVE
ANGULAR 2: 3 KINDS OF DIRECTIVES
COMPONENT, DECORATOR, VIEWPORT
ES6/TYPESCRIPT
@Component({selector: 'hi-greeter'})@View({ template: '<h1>Hello, {{hi.place}}</h1>'})class Hi { constructor() { this.place = 'world'; }}
ES5 (A)
a.Component({selector: 'hi-greeter'}).View({ template: '<h1>Hello, {{hi.place}}</h1>'}).for(Hi)function Hi() { return { this.place = 'world'; };}
ANGULAR 2 = TREES
AN AMAZING HISTORY OF ROUTERS
I N T O
T H E
F U T U R E
NG-ROUTER
• Map pages to urls
• Pass in params
$routeProvider.when('/', {
templateUrl: 'pages/home.html', controller: 'mainController' }).when('/about', {
templateUrl: 'pages/about.html', controller: 'aboutController' });
}
UI-ROUTER
Ng-router features +
Nested states/views
Named states
Resolve data
Route data
Abstract states (inheritance)
onChange, onChangeError
$stateProvider .state('contacts', { abstract: true, url: '/contacts', template: '<ui-view/>'
}) .state('contacts.list', {
url: '/list', views: { 'list': {
templateUrl: 'contacts-list.html’, controller: 'ContactListController', resolve:{ list: function(contacts){
return {'list': contacts.all()};}}},
'info': { templateUrl: 'contacts-view.html',
controller: 'ContactViewController' }
});
<div router-viewport="name"></div>
COMPONENT-ROUTER
Ui-router features +
Routes to components
Naming conventions
Lifecycle hooks
Lazy-loading
Change page titles
$routeConfig = [ { path: '/', component: 'home' }, { path: '/contacts/’,
components: { 'list': 'contactList', 'view': 'contactView' } }];
ROUTER PARTS
WARNING: UNDER DEVELOPMENTEXPECTED RELEASE: maybe next week
?
Things change, but the concepts stay the same.
$ROUTECONFIG
// Routes bind to a controller/class
MyController.$routeConfig = [ {
path: '/user',
component: 'user’, // if named paths, use components: { name: ‘value’, etc. }
as: ‘userState’
} ];
SETUP
<a ng-link=“home”></a> // link to component name
<div ng-viewport></div>
// named routes
<a ng-link=“master:home”></a>
<div ng-viewport=“master”></div>
// params
<a ng-link=“home({greeting: ‘hello’})></a> // accessed by $routeParams
NAMING CONVENTIONS
$stateProvider .state('contacts', { abstract: true, url: '/contacts', template: '<ui-view/>'
}) .state('contacts.list', {
url: '/list', views: { 'list': {
templateUrl: 'contacts-list.html’, controller: 'ContactListController', resolve:{ list: function(contacts){
return {'list': contacts.all()};}}},
'info': { templateUrl: 'contacts-view.html',
controller: 'ContactViewController' }
});
COMPONENT ROUTER
$routeConfig = [ { path: '/', component: 'home' }, { path: '/contacts/’,
components: { 'list': 'contactList', 'view': 'contactView' } }];
COMPONENT: HOME
{ path: '/', component: 'home' templateUrl: './components/home/home.html’, controller: 'HomeController', controllerAs: 'home'}
COMPONENT: CONTACTLIST
{ path: '/', component: 'contactList', templateUrl: './components/contact-list/contact-list.html', controller: 'ContactListController', controllerAs: 'contactList’}
LIFECYCLE HOOKS
1. CONTROLLER INSTANTIATED
THINK
Lazy-load
Dependencies added
angular.module('app', []) .controller('MyController', ['user', '$http', MyController]);
function MyController(user, $http) { this.user = user; this.$http = $http;}
2. CANACTIVATE
THINK
Security
Permission
Before route can change
function MyController(user) { this.user = user;}
MyController.prototype.canActivate = function() { return this.user.isAdmin;};
3. ACTIVATE
THINK
Data
Resolve
Processing
Before route change finishes
function MyController($http) { this.$http = $http;}
MyController.prototype.activate = function() { return this.files = this.$http.downloadFiles();};
4. CANDEACTIVATEBefore each old-route component is removedCalled for each component
THINK
Save Data
Save State
function SaveController($q) { this.$q = $q;}SaveController.prototype.canDeactivate = function() { this.deferred = this.$q.defer(); this.showSaveDialog = true; // return true = can continue return this.deferred.promise();};
5. DEACTIVATEFired for each component removedBut called after canActivate of next route
THINK
Clean upSomeController.prototype.deactivate = function() { return this.removeSelf();};
QUIZ
• WHAT’S A COMPONENT?
• WHAT’S A WEB COMPONENT?
• WHY SHOULD I CARE ABOUT COMPONENTS?
• WHAT ARE THE BENEFITS OF THE NEW COMPONENT ROUTER?
COMPONENTSA N G U L A R +
Shawn McKay@Sh_McK
me@shmck.com