Angular 9 — A New Era Begins

The release candidate for Angular 9 has landed, and this is genuinely a landmark moment for the framework. The excitement isn't just about the release itself — it's about what comes with it. Ivy is now the default rendering engine, and that changes the game in fundamental ways.

_India's premier Angular conference_ is set for 29th February 2020, featuring speakers from the Angular core team. The 2019 edition was a resounding success, and we'd love to see you there this year. Tickets go on sale from 7th November, 7 pm — head over to the ng-india website for details.

?@angular CLI released V9.0.0-RC.0! ???

❤️ Angular 9.0.0-RC.0
? Ivy enabled by default.
????????

Curious about Ivy, but didn't dare before? Here you go!
Thank you #Angular CLI team! pic.twitter.com/gDl9zBUiCn

— Sander Elias @?? (@esosanderelias) November 1, 2019

If that hasn't convinced you yet, take a look at this post from Mathias Raacke. A Hello World application now comes in at just 7 KB — experimental still, but the direction is clear.

With @angular 9 RC0, a hello world app (compressed, no zone.js, no legacy browsers) is now only 7 KB. Nice! pic.twitter.com/8SPSJAEXvS

— Mathias Raacke (@oocx) November 2, 2019

Let's dig into everything else that ships with this release.

New Features

Migration Support for Undecorated Classes

Up through Angular 8, decorators were optional for base classes used by directives and components. The same applied to services that skipped the @Injectable decorator.

export class BasePlain {
  constructor(private vcr: ViewContainerRef) {}
}

@Directive({selector: '[blah]'})
export class DerivedDir extends BasePlain {}

Under Ivy those classes now require decorators as well. When you run ng update, the migration will inject the appropriate decorators automatically. For edge cases that aren't covered, check this document.

FormControlName Now Accepts Numbers

How many times have you written [formControlName]="i" and not thought twice? It worked because Angular secretly tolerated the mismatch — the expected type is string. Without fullTemplateTypeCheck this never surfaced. With Ivy, the type checker won't let that slide. To keep the pattern viable, formControlName now accepts string | number.

<div formArrayName="tags">
  <div *ngFor="let tag of tagsArray.controls; index as i">
    <input [formControlName]="i">
  </div>
</div>

TestBed.inject Replaces TestBed.get

Angular 8 introduced a breaking change where TestBed.get would no longer accept a string value. That change was reverted after it caused widespread disruption across large codebases. Now that TestBed.inject offers a type-safe alternative, the older TestBed.get has been formally deprecated.

TestBed.get(ChangeDetectorRef) // returns any

TestBed.inject(ChangeDetectorRef) // returns ChangeDetectorRef

Static Flag in ViewChild Gets a Default

Angular 8 made the static flag mandatory for ViewChild. The property remains, but you no longer have to explicitly pass { static: false } — it's the default. When you migrate with ng update, any occurrences of that explicit setting will be cleaned up automatically.

@ViewChild(ChildDirective) child: ChildDirective;
@ViewChild(ChildDirective, { static: false }) child: ChildDirective; // similar to above code

ng-add for @angular/localize

Localization setup is simpler now. Run ng add @angular/localize and the CLI will install the package and wire up the required imports in your polyfills.

Stricter Template Type Checking

One long-standing complaint has been that Angular templates don't get the same type-safety scrutiny as plain TypeScript. That changes now — directives like *ngIf and *ngFor, as well as pipes, are covered. Three levels of checking are available:

  • Basic Mode: set fullTemplateTypeCheck: false
  • Full Mode: set fullTemplateTypeCheck: true
  • Strict Mode: set fullTemplateTypeCheck: true and strictTemplates: true

See the official docs for full details.

TypeScript 3.6 Required

The framework now requires TypeScript 3.6. Here's a handy reference from Lars Gyrup Brink Nielsen mapping Angular versions to their supported TypeScript versions.

ModuleWithProviders Gains Generics

Library authors take note: ModuleWithProviders must now be parameterized with the module type using ModuleWithProviders<T>. This is no longer optional.

The migration schematic handles this automatically, so ng update will apply the necessary changes.

Before:

@NgModule({ ...}) export class MyModule {
 static forRoot(config: SomeConfig): ModuleWithProviders {
   return {
         ngModule: SomeModule,
         providers: [{ provide: SomeConfig, useValue: config }]
   };
 }
}

After migration:

@NgModule({ ...})
export class MyModule {
  static forRoot(config: SomeConfig): ModuleWithProviders<SomeModule>
{
   return {
         ngModule: SomeModule,
         providers: [{ provide: SomeConfig, useValue: config }]
   };
 }
}

Schematics Run Against Libraries Too

ng update has always handled code migrations, but it previously skipped Angular libraries. In Angular 9, that's no longer the case — all migration schematics will be applied to library projects as well. If you maintain an Angular library, this keeps your code aligned with the latest standards.

entryComponents Are Gone

If you've ever built a popup, you've likely encountered entryComponents. It was necessary for dynamically loading components that weren't referenced in a template. With Ivy, that requirement evaporates entirely.

Breaking Changes

tslib No Longer a Dependency

Angular has dropped its dependency on tslib. In previous versions, it was bundled as part of the framework's dependencies. If you're not using the Angular CLI, you may need to install tslib manually.

Forms

  • ngForm: The <ngForm></ngForm> selector is no longer valid. Switch to <ng-form></ng-form>.
  • NgFormSelectorWarning: This directive, deprecated since Angular 6, has now been removed. Its purpose was to emit warnings when the deprecated [ngForm](https://angular.io/api/forms/NgForm) selector was in use.
  • FormsModule.withConfig: Removed. Use FormsModule directly. The old withConfig method accepted options like:

opts: { warnOnDeprecatedNgFormSelector?: "never" | "once" | "always"; }

  • The deprecated type RenderComponentType has been removed. Use RendererType2 instead.
  • The deprecated type RootRenderer has been removed. Use RendererFactory2 instead.

Angular Localization

  • Translations loaded via loadTranslations() must now use MessageId as the key, rather than the previous SourceMessage string.
  • The global $localize function is now imported from @angular/localize/init. Previously it was from @angular/localize.
  • The functions loadTranslations() and clearTranslations() are now imported from @angular/localize. The old path was @angular/localize/run_time.

Service Worker

The versionedFiles property has been removed from ngsw-config.json.

Before

"assetGroups": [
  {
    "name": "test",
    "resources": {
      "versionedFiles": [
        "/**/*.txt"
      ]
    }
  }
]

After

"assetGroups": [
  {
    "name": "test",
    "resources": {
      "files": [
        "/**/*.txt"
      ]
    }
  }
]

Angular Bazel

  • The ng_setup_workspace() function from @angular/bazel is gone. Angular now assumes you'll fetch rules_nodejs in your WORKSPACE file. Remove any calls to this function and its associated load statement.
  • If you were using protractor_web_test_suite from @angular/bazel, move to the @bazel/protractor package instead.

Deprecations

  • TestBed.get is deprecated in favor of the type-safe TestBed.inject.

For the complete migration guide, see the official docs. Ivy itself deserves a dedicated post — it's a substantial topic on its own, and we'll cover all its features in an upcoming article.

Angular CLI

CLI Version Verification

A new check verifies whether the installed CLI matches the latest published version. If it doesn't, running ng update will fetch the latest version as a temporary package to execute the migration.

Mix and Match Configurations

Previously, ng build --configuration required you to create a complete new entry for any overrides. Now you can combine configurations directly: ng build --configuration=prod,testing. In the testing configuration, you only define the settings you want to override.

ng-add Options for Package Authors

Another update for Angular library authors: ng add can now specify whether the package should be added to dependencies or not.

You can declare this in package.json:

ng-add : { 
     "save": false | true | 'dependencies' | 'devDependencies'
}

Type Option for Component Schematics

Running ng g c user generates a UserComponent class. With the new type option, you can specify the component kind. For instance, ng g c user --type="dialog" produces a class named UserDialog.

Auto-Generated Interceptors

Creating an interceptor was a manual chore until now. In Angular 9, ng g i custom will scaffold a CustomInterceptor class for you.

App-Shell Schematic Simplified

The --clientProject flag was previously required to generate an app-shell. It's now optional — when omitted, the default project will be used.

Minimal Apps Don't Generate Spec Files

Creating an app with --minimal=true skips e2e and unit testing setup. However, subsequent ng g commands would still add a spec.ts file. From Angular CLI 9 onwards, that's handled correctly.

Simplified Multi-Select Prompts

Building a multi-select prompt previously required a host of extra options. With Angular 9, the configuration is much simpler, as shown below.

test: {
  type: 'array',
  'x-prompt': {
    'type': 'list',
    'multiselect': false,
    'items': [
      {
        'value': 'one',
        'label': 'one'
      },
      {
        'value': 'two',
        'label': 'two'
      },
    ],
    'message': 'test-message',
  },
}

npmrc File Path Support

The NPM_CONFIG_USERCONFIG and NPM_CONFIG_GLOBALCONFIG environment variables are now respected by the Angular CLI, taking precedence over the global .npmrc file. See the npm docs for further information.

Breaking Change

  • The styleext and spec options have been removed from the CLI. Use style and skipTests in their place.

Angular Component

New Clipboard Module

A clipboard component has been added as part of the @angular/cdk package.

For a walkthrough on using it, check out this article from Tim Deschryver.

https://medium.com/angular-in-depth/use-the-new-angular-clipboard-cdk-to-interact-with-the-clipboard-be1c9c94cac2

HammerJS Becomes Optional

Previously, including hammerjs was mandatory for adding gesture support to your app. That is no longer the case — the internal implementations have been stripped out, and the library is now an optional dependency. For gesture handling, you can import HammerModule from @angular/platform-browser.

Introducing the Google Maps Package

A new @angular/google-maps package has landed, simplifying what was once a notoriously tricky integration process. The package has been verified across a range of devices. For a step-by-step walkthrough, check out the blog post by Tim Deschryver.

Google Maps as an Angular Component

The latest Angular Component release brings the second official component from the @angular/component family: a fully-fledged Google Maps component. This marks a significant shift toward easing map-based UI development.

For related reading: https://medium.com/angular-in-depth/use-the-new-angular-clipboard-cdk-to-interact-with-the-clipboard-be1c9c94cac2

Breaking Changes to Watch

  • Direct imports from @angular/material are no longer supported for components. Instead, you must use the specific secondary entry-points, for example @angular/material/button.
  • The MAT_CHECKBOX_CLICK_ACTION token has been deprecated. Use MAT_CHECKBOX_DEFAULT_OPTIONS as its replacement.

It is genuinely thrilling to see Ivy stabilize and reach a production-ready state, and I imagine the excitement is shared across the community. The CLI has gained numerous productivity-boosting features, and it is encouraging to witness the addition of polished components such as the map and clipboard integrations to Angular Material. With Ivy now in the mix, there is plenty of room for further growth — so hang tight, because exciting times lie ahead for Angular, and you have every reason to be enthusiastic.

A heartfelt thank you to the community members who made a Japanese translation available:

https://www.graat.co.jp/blogs/ck38hopvsqxw60991eco8zmsx?source=post_page—–b3dbb4078c47———————-