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

Angular Migration Workshop

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

Angular Migration Workshop

Avatar for Manfred Steyer

Manfred Steyer PRO

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