Migrate AngularJS to Angular using UpgradeModule (Part 3)

Danny Cornelisse
10-12-2018

Part 1: Setting up the hybird app

Part 2: Refactor constants, values and services

Refactoring angularJS to Angular

The previous steps explained how to set up the hybrid application (step 1) and how to refactor constants, values and services (step 2). This next step will dive into refactoring angularJS components to angular components

Refactor components

Like services, the best strategy to refactor components is to start with the smallest components. That is because angularJS element components are difficult to use inside Angular component templates. The second rule of thumb is to refactor the components with the least dependencies such as bindings and requires. The basic idea of refactoring an angularJS component to an Angular component is to use the hybrid approach. The refactored component is written in Angular but will be both available as an angularJS component as well as an Angular component. To do that, the refactored Angular component will have to be downgraded (!) to be used as an angularJS component. The following steps may be taken to refactor a component:

  1. Copy the controller function to component.js file
  2. Remove all IIFE’s
  3. Change controller function to component class and export it: function NewController => export class NewComponent
  4. Import Component from @angular/core
  5. Decorate Class with @Component
  6. Add styleUrls
    import { Component, Inject, OnInit, OnDestroy } from '@angular/core';
    
    @Component({
      selector: 'meyn-new-component',
      templateUrl: './component.new.html' ,
      styleUrls: ['./header.component.scss']
    })
    export class NewComponent implements OnInit, OnDestroy {
    

    Step 1-4 alternative: Create a component using the Angular CLI and copy all methods, private functions and variables from controller to class.

  7. Remove const vm = this; variable. Angular classes use this to reference methods/members of the class
  8. Refactor all methods in the angularJS controller function:
    1. If method is bound to this keyword: Change vm.firstMethod to public firstMethod
    2. If variable is scoped to function: Change const myVar to private readonly myVar
    3. If function is private: Change function myPrivateFn to private myPrivateFn
  9. Change vm.$onInit and vm.$onDestroy to ngOnInit and ngOnDestroy.
    Note: !important!! Do not use arrow function syntax ngOnInit = () => {}
    This won’t trigger the lifecycle hook! Use ngOnOnit() {} instead
  10. For all component bindings, import @Input from angular core and inject in component:
    @Input: myInput: any;
  11. For all component bindings, import @Input from angular core and inject in component:
    @Input: myInput: any;

    !important!! when using bindings in angularjs template, use [], () or [()] marks for attributes:

    [my-input]="$ctrl.testy". Otherwise, property won't bind!
  12. For all component ‘require’s, import @Input from angular core and inject in component.for each require, add input of the same name:
    export class MyComponent {
      @Input() parent: any;
    

    These bindings need to input as a html attribute:

    [parent]="MyCtrl" in case of angularjs template
    [parent]="this" in case of angular template
    
  13. Create constructor for class and add al angularJS services and Angular Services:
    constructor (
            @Inject('$http') public $http: any, 
        private myService: MyService
    ) { }
    
  14. Don’t forget to register angularJS services in app.module.ts:
    @NgModule({
      providers: [
       {
          provide: '$q',
          useFactory: ($injector: any) => $injector.get('$q'),
          deps: ['$injector']
      },
      …
    
  15. Downgrade (!) this new Angular Component to service to angularjs directive(!) using downgradeComponent at the end of the file. Now, the component can be used as both ann Angular and angularJS component:
    declare var angular: angular.IAngularStatic;
    import { downgradeInjectable } from '@angular/upgrade/static';
    
    export class MyComponent { … }
    
    angular.module('app').directive('myComponent', downgradeComponent(MyComponent));
    
  16. Refactor angularJS html template to use Angular attribute directives. This needs to be done very carefully.

An alternative to using angularJS components in Angular html template, they can be upgraded, although it is not recommendable:

https://angular.io/api/upgrade/static/UpgradeComponent

For a quick reference for upgrading angularJS template directives to Angular template directives, refer the excellent guide by the angular team:

https://angular.io/guide/ajs-quick-reference.

Part 4 will be about refactoring angularJS directives.

LEAVE A REPLY

you might also like