Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Angular Migration Workshop

Angular Migration Workshop

Manfred Steyer

October 25, 2016
Tweet

More Decks by Manfred Steyer

Other Decks in Programming

Transcript

  1. About me … • Manfred Steyer • SOFTWAREarchitekt.at • Trainer

    & Consultant • Google Developer Expert • Focus: Angular Page  2 Manfred Steyer
  2. Goals • Find out how to prepare for a migration

    to Angular 2 • Find out how to migrate to Angular 2 step by step
  3. Contents • General Approaches for Migrating to Angular 2 •

    Preparation • Controller-as • Components in AngularJS 1.5+ • One Way Binding • Communication between Components in AngularJS 1.5+ • Routing to Components • TypeScript and AngularJS 1.x • Webpack • Migrating to Angular 2 with ngUpgrade • Demonstration without Exercises • Exercises
  4. Page  9 FlightCard FlightSvc FlightList App 1 1 1

    1 Migrating step by step with ngUpgrade
  5. Migrating step by step with ngUpgrade Page  11 FlightCard

    FlightSvc PassengerCard PassengerSvc FlightList PassengerList App 1 1 1 1 2 2 2
  6. Migrating step by step with ngUpgrade Page  12 FlightCard

    FlightSvc PassengerCard PassengerSvc FlightList PassengerList App 2 2 2 2 2 2 2
  7. Controller-as Page  22 Controller Template Scope myCtrl <div ng-controller="Controller

    as myCtrl"> <input ng-model="myCtrl.from"> <input ng-model="myCtrl.to"> […] </div> new
  8. Constructor-Function for Controller Page  23 function FlightListController($http, $log) {

    this.from = "Graz"; this.to = "Hamburg"; this.selectedFlight = null; this.flights = []; this.message = ""; this.search = function() { … } this.select = function() { … } }
  9. Controller-as and UI-Router Page  24 $stateProvider.state('home', { url: '/home',

    templateUrl: '/app/home/home.html', controller: 'home', controllerAs: 'home' })
  10. Controller-as and Directives Page  25 app.directive('passengerCard', function() { return

    { restrict: 'E', templateUrl: '…', controller: function() { this.select = function() { this.selectedItem = this.item; } }, controllerAs: 'myCtrl', scope: { item: '=', selectedItem: '=' }, bindToController: true } }); <passenger-card item="myPassenger" selectedItem="selected"> </passagier-card> <a ng-click="myCtrl.select()"> … </a>
  11. Controller-as and Directives Page  26 app.directive('passengerCard', function() { return

    { restrict: 'E', templateUrl: '…', controller: function() { this.select = function() { this.selectedItem = this.item; } }, controllerAs: 'myCtrl', bindToController: { item: '=', selectedItem: '=' } } }); <passenger-card item="myPassenger" selectedItem="selected"> </passagier-card> <a ng-click="myCtrl.select()"> … </a>
  12. Components in Angular 1.5 Page  27 app.component('passengerCard', { templateUrl:

    '[…]', controller: function() { this.select = function() { this.selectedItem = this.item; } }, controllerAs: 'myCtrl', // <-- Default: $ctrl bindings: { item: '=', selectedItem: '=' } });
  13. Components in ng1.5 Page  28 restrict: 'E' scope: {}

    bindToController controllerAs (Default $ctrl) No compile No link No replace
  14. Why components in AngularJS 1.5+ • Alignment to Angular 2

    • Components can be migrated to Angular 2 one by one
  15. Data Binding in Angular 1.x Page  31 Model Model

    Directive Nearly everything can depend on everything Solution: Multiple Digest-Cycles
  16. Component Tree in Angular 2 Page  32 Component for

    whole App Component (e. g. list) Component (e. g. list-item) Component (e. g. list-item)
  17. Rules for Property Bindings • A Component only depends on

    its own data (and indirectly on its parent‘s data) • A Component must not depend on its childrens‘ data! • Dependency Graph is a tree • Angular only needs one digest cycle to update tree Page  33
  18. Property Binding Page  34 model item item {{ item.title

    }} {{ item.title }} [http://victorsavkin.com/post/110170125256/change-detection-in-angular-2]
  19. Event Bindings (One Way, Bottom/Up) Page  35 {{ item.title

    }} {{ item.title }} Event-Handler Event-Handler
  20. Event Bindings (One Way, Bottom/Up) • No digest cycles for

    propagating events • But: Events can change state  Property Bindings Page  36
  21. Property and Event Bindings Page  37 Performing Property Bindings

    Executing Event Handlers Event occurs App is ready All handlers executed Properties bound
  22. Two Way Binding in Angular 2 • Combination of Property-

    and Event-Binding • For instance: ngModel and ngModelChange • Good performance because of unidirectional data flow • Syntactical Sugar: <input [(ngModel)]="departure">
  23. passenger-card Page  40 passenger-card item selectedItem > > >

    selectedItemChange passenger selectedPassenger
  24. One Way Bindings Page  41 app.component('passengerCard', { templateUrl: '[…]',

    controller: function() { this.select = function() { this.selectedItem = this.item; this.selectedItemChange(this.item); } }, controllerAs: 'myCtrl', // <-- Default: $ctrl bindings: { item: '<', selectedItem: '<', selectedItemChange: '&' } });
  25. Tab Component app.component('tab', { require: { tabs: '^tabs' }, controller:

    function() { this.$onInit = function() { this.tabs.register(this); } }, bindings: { title: '@' }, transclude: true, template: '[...]' });
  26. Tabs Component app.component('tabs', { controller: function() { this.tabs = [];

    this.register = function(tab) { this.tabs.push(tab); } this.activate = function(tab) {…} this.$postLink = function() { if (this.tabs.length == 0) return; this.activate(this.tabs[0]); } } […] });
  27. Components and UI-Router 0.x Page  50 $stateProvider.state('passenger-list', { url:

    '/passenger-list', template: '<passenger-list></passenger-list>' });
  28. Controller in TypeScript Page  53 export class FlightSearchController {

    public from: string; public to: string; constructor() { this.from = "Vienna"; this.to = "London"; } public search() { […] } public select() { […] } }
  29. tsconfig.json { "compilerOptions": { "target": "es5", "module": "commonjs", "moduleResolution": "node"

    "outDir": "dist/ts", "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, }, "exclude": [ "node_modules" "dist" ] }
  30. Typings • Files that define types for JavaScript libraries •

    TypeScript uses them to work with preexisting JavaScript code • Huge repository: http://definitelytyped.org/ • typings install angular • npm install @types/angular
  31. Webpack Page  58 File A File B File C

    File D File E Entry Point Bundle Bundle Loader (z.B. .ts  .js)
  32. Why webpack • Works declarative and not imperative • Aligns

    to NodeJS convetions • Fast solution • Huge community
  33. webpack.config.js […] module: { loaders: [ […] { test: /\.ts$/,

    loaders: [ 'angular2-template-loader', 'awesome-typescript-loader‚ ] } ] }, […]
  34. Using ngUpgrade var app = angular.module('flight-app', [...]); [...] const upgradeAdapter

    = new UpgradeAdapter(forwardRef(() => AppModule)); @NgModule({ imports: [ ... ], declarations: [ ... ], providers: [ ... ] }) class AppModule { }
  35. Using ngUpgrade var app = angular.module('flight-app', [...]); [...] const upgradeAdapter

    = new UpgradeAdapter(forwardRef(() => AppModule)); @NgModule({ imports: [ ... ], declarations: [ ... ], providers: [ ... ] }) class AppModule { } // Upgrade ng1 services and providers // Downgrade ng2 services and providers
  36. Using ngUpgrade var app = angular.module('flight-app', [...]); [...] const upgradeAdapter

    = new UpgradeAdapter(forwardRef(() => AppModule)); @NgModule({ imports: [ ... ], declarations: [ ... ], providers: [ ... ] }) class AppModule { } // Upgrade ng1 services and providers // Downgrade ng2 services and providers upgradeAdapter.bootstrap(document.body, ['flight-app']);
  37. Component Controller Page  72 @Component({ selector: 'flight-sarch', templateUrl: 'flight-search.html'

    }) export class FlightSearchComponent { from: string; to: string; flights: Array<Flight>; constructor(http: Http) { } search() { [...] } select(flug: Flight) { [...] } }
  38. Template Page  73 <input [(ngModel)]="from"> <input [(ngModel)]="to"> <button [disabled]="!from

    || !to" (click)="search()"> Search </button> <table> <tr *ngFor="let flight of flights"> <td>{{flug.id}}</td> <td>{{flug.datum}}</td> <td>{{flug.von}}</td> <td>{{flug.nach}}</td> </tr> </table>
  39. AppModule Page  75 @NgModule({ imports: [ BrowserModule, HttpModule, FormsModule

    ], declarations: [ AppComponent, FlightSearchComponent ], providers: [ FlightService ], bootstrap: [ AppComponent ] }) export class AppModule { }
  40. Your turn • Labs (Step-by-Step): https://goo.gl/vCEdBy • If there are

    any questions, feel free to ask. • Solution: https://goo.gl/RRYGrF • Slides: https://goo.gl/oC6jBn Contact [mail] [email protected] [blog] SOFTWAREarchitekt.at [twitter] ManfredSteyer