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: trueandstrictTemplates: 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
FormsModuledirectly. The oldwithConfigmethod accepted options like:
opts: { warnOnDeprecatedNgFormSelector?: "never" | "once" | "always"; }
- The deprecated type
RenderComponentTypehas been removed. UseRendererType2instead. - The deprecated type
RootRendererhas been removed. UseRendererFactory2instead.
Angular Localization
- Translations loaded via
loadTranslations()must now useMessageIdas the key, rather than the previousSourceMessagestring. - The global
$localizefunction is now imported from@angular/localize/init. Previously it was from@angular/localize. - The functions
loadTranslations()andclearTranslations()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/bazelis gone. Angular now assumes you'll fetchrules_nodejsin your WORKSPACE file. Remove any calls to this function and its associatedloadstatement. - If you were using
protractor_web_test_suitefrom@angular/bazel, move to the@bazel/protractorpackage instead.
Deprecations
TestBed.getis deprecated in favor of the type-safeTestBed.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
styleextandspecoptions have been removed from the CLI. UsestyleandskipTestsin 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.
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/materialare no longer supported for components. Instead, you must use the specific secondary entry-points, for example@angular/material/button. - The
MAT_CHECKBOX_CLICK_ACTIONtoken has been deprecated. UseMAT_CHECKBOX_DEFAULT_OPTIONSas 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———————-
