Search code examples
angularangular-ivy

Template errors after migration Angular 6 -> 9


I just did the migration from Angular 6 to Angular 9, one of the most important dependency could not be used on Angular 6.

I follow the steps from ng update:

  • ng update
  • ng update rxjs
  • ng update @angular/cli
  • ng update @angular/core

The problem is that I have now a lot of template errors, all relate to the same problems.

  • No directive found with exportAs 'ngModel'
  • No directive found with exportAs 'ngForm'

I found nothing on the web relate to theses error on v9 (only on v2).

Here is some parts related to the error:

  • For the error about ngModel
<input type="text" class="form-control style-input-size" name="UserUpdatedUsername" [(ngModel)]="UserUpdated.username" #myKronozUserUpdatedUsername="ngModel" mdbActive required>
  • For the error about ngForm
<form #editUserForm="ngForm" (ngSubmit)="editUserForm.valid && saveUpdateUser()" novalidate class="style-form-edit-user">

FormsModule is well imported in the app.module.ts (this is the only module inside the app). app.module.ts:

import { FormsModule } from '@angular/forms';

@NgModule({
  imports: [FormsModule]
})
export class AppModule {
}

package.json:

  "dependencies": {
    "@agm/core": "^1.1.0",
    "@angular/animations": "^9.0.5",
    "@angular/common": "^9.0.5",
    "@angular/core": "^9.0.5",
    "@angular/forms": "^9.0.5",
    "@angular/platform-browser": "^9.0.5",
    "@angular/platform-browser-dynamic": "^9.0.5",
    "@angular/platform-server": "^9.0.5",
    "@angular/router": "^9.0.5",
    "@ngx-translate/core": "^10.0.2",
    "@ngx-translate/http-loader": "^3.0.1",
    "angular-csv-files": "^1.0.0",
    "chart.js": "2.5.x",
    "classlist.js": "1.1.x",
    "core-js": "2.4.x",
    "crypto-js": "^3.1.9-1",
    "easy-pie-chart": "2.1.x",
    "font-awesome": "4.7.x",
    "hammerjs": "2.0.x",
    "jarallax": "^1.10.3",
    "moment-timezone": "^0.5.21",
    "ng-html-util": "1.0.x",
    "ng-recaptcha": "^4.3.0",
    "ng-uikit-pro-standard": "/!\ sensible value /!\",
    "ng2-file-upload": "^1.3.0",
    "ngx-facebook": "^2.4.0",
    "ngx-pagination": "^3.2.1",
    "node-sass": "^4.13.1",
    "rxjs": "^6.5.4",
    "rxjs-compat": "^6.3.3",
    "screenfull": "3.3.x",
    "smoothscroll-polyfill": "0.3.x",
    "tslib": "^1.10.0",
    "web-animations-js": "^2.3.2",
    "zone.js": "~0.10.2"
  },
  "devDependencies": {
    "@angular/cli": "^9.0.5",
    "@angular/compiler-cli": "^9.0.5",
    "@angular/language-service": "^9.0.5",
    "@angular/compiler": "^9.0.5",
    "@types/jasmine": "2.5.38",
    "@types/node": "^12.11.1",
    "codelyzer": "^5.1.2",
    "jasmine-core": "~2.5.2",
    "jasmine-spec-reporter": "~3.2.0",
    "karma": "~1.4.1",
    "karma-chrome-launcher": "~2.0.0",
    "karma-cli": "~1.0.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "karma-coverage-istanbul-reporter": "^0.2.0",
    "protractor": "~5.1.2",
    "ts-node": "~3.2.0",
    "tslint": "~5.7.0",
    "typescript": "~3.7.5",
    "webpack": "^4.3.0",
    "@angular-devkit/build-angular": "~0.900.5"
  }

Did I miss something for the migration ? Thanks.


Solution

  • You're getting errors because template only variables have been removed in Angular 9. This was done because they were typed as any and allowed for mutations. In general, this was an anti-pattern. Going forward, your elements will be strongly typed.

    In Angular versions <= 8, the code below was valid. #TranslateBtn you could reference a translate property because it was typed as any.

    <button
      #translateBtn
      (click)="translateBtn.translate = !translateBtn.translate"
    >
      Translate
    </button>
    

    In Angular 9, #translateBtn will be of type HTMLButtonElement, which does not have the translate property. Instead, you would replace that functionality with an event calling a function on your component.

    HTML:

    <button (click)="ontTranslate()">
      Translate
    </button>
    

    TS:

    export class PeopleListComponent {
      translateToWookiee = false;
    
      onTranslate(): void {
        this.translateToWookiee = !this.translateToWookiee;
      }
    }
    

    My answer came from this blog article from Brian Love, Google Developer Expert in Angular and Web Technologies.