Angular is a popular framework for JavaScript/ TypeScript application development. This open source framework by Google is continuously enhanced and new features are added on a regular basis.
Angular 9 is special! It’s a key release in the last three years. Having said that, for most applications, the upgrade is smooth with minimal impact and few changes that need developer intervention.
However, Angular 10 is relatively a smaller update (compared to other major releases).
In this tutorial, we will go through some new features of Angular 9 and Angular 10.
New Features in Angular 9 and Angular 10
Angular’s semantic versioning includes three parts – major, minor and patch version numbers. As an example, v10.0.1 refers to major version 10, minor version 0 and patch version 11.
Angular has a predictable release schedule. There has been a major release every six months.
Angular 9 being a major version, comes with a few breaking changes. Developer intervention is required while upgrading a project from Angular 8 to Angular 9, and to version 10.
Angular best practices describe a deprecated feature will continue to be available for two major releases. This gives enough breathing room for teams and developers to update their code.
Additionally, a warning on the console in dev mode highlights the need to refactor code. (Production build does not show the warning). Follow the link to see a complete list of deprecations https://angular.io/guide/deprecations
At the time of writing this article, the minor version of Angular 10 is 0 and patch version is 1. A minor version upgrade wouldn’t need developer intervention. As the name indicates, they are few minor upgrades in the framework features. Patch releases are frequent, often weekly and include bug fixes.
#1. How to upgrade to Angular 10
To upgrade your project to Angular 10 using Angular CLI, use the following command.
ng update @angular/cli @angular/core
While the above command upgrades CLI and Angular core, we need to run the update command on individual repos. In this example, my application uses Angular Material and the CDK. Run the following Angular CLI command to upgrade version 10.
ng update @angular/material @angular/cdk
An application, https://update.angular.io/ lists all changes required while upgrading the framework. It lets us select current Angular version and the target version.
It’s always advisable to upgrade to the latest Angular version. However, it is recommended to move step by step between major versions. That is, if your project is on Angular 8, migrate first to the version 9 commit and test the changes. Next, upgrade to Angular 10 (latest version as of this writing). To upgrade to a specific version, say version 9 (as opposed to the latest version 10) use the following command
ng update @angular/cli@9 @angular/core@9
#2. Ivy
First and foremost, along with Angular 9, a new and better compiler and run time, Ivy is introduced. It’s the default for Angular 9 applications. View Engine, the older compiler and run time, is still available and actively used by many projects and libraries.
An Angular 9 application using Ivy can have dependencies (libraries and packages) that are built with the View Engine. A tool ngcc (Angular Compatibility Compiler) helps with the backward compatibility. It works on node modules and produces Ivy compatible version. Angular CLI runs the ngcc command as required.
It’s preferred to use View Engine for Angular libraries. This is because libraries need to stay compatible with applications that use View Engine. Moreover, a library build with View Engine is still compatible with Ivy (compiled by ngcc).
Note: Angular 9.1.x improved ngcc speed. The tool runs in-parallel compiling multiple libs at a time.
Let’s have a look at what changed with the introduction of Ivy and Angular 9.
2.1 Entry Components
Angular doesn’t need imperative components specified as entry components. Ivy discovers and compiles components automatically.
What are entry components? Angular loads components in one of the two ways, declaratively or imperatively. Let’s elaborate.
Declarative:
The HTML template is declarative. When we include a component as a child in the HTML template of another component using a selector, it is declarative.
For example, consider the following todo application’s code snippet. An AppComponent template uses two other components – create-todo and todo-list. They are included in the application declaratively.
<mat-toolbar color="primary"><h1>Your Todos</h1></mat-toolbar>
<div>
<app-create-todo></app-create-todo>
<app-todo-list></app-todo-list>
</div>
Imperative
Few components are included in the application imperatively. They are not included in the HTML template.
For example, the App Component is bootstrapped at the time of loading the application and the root module. Even though it’s in index.html, it’s not part of a component template. The Router loads few other components. These are not in a template of any kind. Check out the following code snippet:
@NgModule({
declarations: [ // Removed code for brevity ],
imports: [ // Removed code for brevity ],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
--- app-routing.module.ts ---
const routes: Routes = [ { path: '', component: TodoListComponent } ];
Router and the bootstrap process automatically adds the above components to entry components’ list. As a developer, we don’t have to do anything special.
However, with Angular 8 (and below), if we create a component using ViewContainerRef and load them programmatically (instead of HTML template), we need to explicitly identify them as entry components. We may add them to entryComponents[] – one of the fields in NgModule() decorator. We may also use ANALYZE_FOR_ENTRY_COMPONENTS, a DI token that creates entry components using the list of references in useValue property. The framework used entry components list for tree shaking.
This is no longer required with Ivy. The compiler and the run time identify the dynamic components. Tree shaking continues to work without explicitly creating entry components.
For an elaborate read on Entry Components, use the links in the References section at the end of the article.
2.2 Bundle size improvement with Ivy
Tree shaking is better with Ivy.
Tree shaking is a process of eliminating dead code (unused code) in the bundles. With tree shaking, Angular release notes describes an improvement in the range of 2% to 40% depending on nature of the application.
Few applications might not use all Angular framework features. With better tree shaking, unnecessary functions, classes and the other code units are excluded from the generated bundles. With Ivy, there is also an improvement in factory sizes generated by the framework.
See Figure 1 depicting bundle size improvement
Figure 1: Reference: Angular Blog (https://blog.angular.io/version-9-of-angular-now-available-project-ivy-has-arrived-23c97b63cfa3)
2.3 Better Debugging with Ivy
With the framework, a global object “ng” is available in the application. This object was available even before Ivy. However, version 9 onwards, the API is easy to use. We can use it for debugging, while in development mode.
Consider the following example. In the to-do sample, we can select the CreateTodo component using getComponent() API on the object, ng. It takes a DOM element as an argument.
In Figure 2, we used document.getElementsByTagName(‘component-selector-name’) for the element. Notice, as we type in a value in the text field, component state is shown on the field (on Google Chrome console).
Figure 2: The ng object prints component state on the browser console
Note: Another way to retrieve the component is to select the element in HTML (DOM) and use $0 (instead of document.getElementsByTagName()), which returns the component for the selected element.
See figure 3 for other useful API with ng (for debugging),
Figure 3: Useful Debugging APIs with ng
ng.applyChanges() – trigger change detection on the component
ng.getContext() – returns context, which is objects and variables with ngFor. Figure 4 shows getContext on second item in the todo list. See Google Chrome console.
Figure 4: getContext() API on the ‘ng’ object in action
ng.getDirectives() – Similar to getComponent(), this method returns directives associated with the selected element.
ng.getHostElement() – Returns parent DOM element of the selected component or the directive.
ng.getInjector() – Returns injector associated with the element, component or directive
ng.getListeners() – Returns Angular event listeners associated with the DOM element.
ng.getOwningComponent() – Returns the parent component to the selected DOM element.
ng.getRootComponents() – Returns a list of root components associated with the selected DOM element. See figure 5.
Figure 5: Result of getRootComponents() API on the ‘ng’ object
2.4 Better template type checking and error messages
Angular version 9 and above supports three modes for type checking.
Strict mode: Supported only with Ivy. The strict mode helps identify maximum number of type problems with the templates. To enable the strict mode, set a flag strictTemplates to true in the TypeScript configuration file, tsconfig.json
The strict mode enables
a. Type checking for @input fields on components and directives
b. Type checking on $event in components and directives
c. Type checking includes generics
d. Type checking on context variables while using *ngFor
Note that the strict mode conforms to strictNullChecks flag in the template. The strictNullChecks mode needs to be enabled in tsconfig.json. The strictNullChecks also constraints TypeScript code to set null and undefined only when defined as a union type.
Look at Figure 6. For the first two variables, aNumericVariable and aNumericVariable2, we can’t set a value null or undefined. It throws an error, rightly so. Consider the last two lines. When used as a union type, we may set null or undefined as values on the variable.
Figure 6: Errors in strict mode
fullTemplateTypeCheck: It’s less constrained than the strict mode and is a subset of the latter. In addition to Ivy, it works on View Engine as well. It Type checks context for *ngFor along with the views *ngIf and <ng-template>. It does not type check generics.
To enable fullTemplateTypeCheck, set the value true in tsconfig.json. Please note, if both fullTemplateTypeCheck and strictMode are enabled, strict mode takes precedence.
Figure 7: Configuration to toggle full template type check or strict mode.
Basic Mode: It is a basic type checking in HTML templates. It checks the object structure while using data binding. Consider the following sample. A sampleTodo object (of type Todo) may have fields id, title or isComplete. Type checks the template and returns an error that a dummy field doesn’t exist on sampleTodo.
Figure 8: Template type check in basic mode
An aspect you might have noticed in Figure 8 is that the message highlights the error better than before. Angular 9 has improved on formatting and showcasing compiler error messages. Following is another example with the build command (the build npm script).
Figure 9: Better error messages with Angular 9 in component templates.
#3. Angular CLI Strict Mode
Angular 10 supports creating a new project in strict mode. While creating a new project, run the CLI command with the –strict option. See the following:
ng new –strict
The strict mode helps maintainability of the project by:
– Turning on strict mode with TypeScript and Angular Templates’ type checks.
– Lint rule that alerts usage of any type.
– Better tree shaking and improvements in bundle size.
#4. Additional options with providedIn
Some new values are added with the @injectable decorator. It is used with Angular services.
platform: Creates a singleton service instance available for all applications on the page.
any: Creates a singleton instance per each Angular module
Earlier, the framework allowed using a value ‘root’ with providedIn. With it, a singleton instance got created for the root module. Hence, one instance for the application.
Use @injectable decorator on an Angular service so that the compiler generates required metadata. Injector creates an instance of the service. It uses the metadata including service’s dependencies.
#5. Lazy load modules
Recent ECMA script update ES 2020 introduced dynamic import of JavaScript modules. This feature is in Stage-4 now, and is supported by all major browsers. Follow the link to read more about the ES 2020 feature. See the following code snippet for an example,
import (‘./create-todo.js’).then((module) => {
// access any exported functions from lazy loaded module
// using the module object
});
Angular modules loaded eagerly, by default. To delay loading the modules on-demand, Angular traditionally used a string syntax (eg. ./path-to-lazy-module/a-lazy.module#ALazyModule). When a user navigated to a route, the module got lazy loaded. Hence this string was specified as a value for loadChildren field in the route configuration.
This syntax was deprecated in Angular 8. Use the new ES2020 syntax in the route configuration. See an example in the code snippet below. It is important to change the syntax with Ivy. Ngc depends on JavaScript dynamic imports to discover lazy loaded modules
const routes: Routes = [{
path: ‘create-todo’,
loadChildren: () => import('./todo/create-todo.module').then(m => m.CreateTodoModule) }];
#6. Angular CLI Date Range
Angular Material 10 adds support for date range. In addition to the current component functionality to select a date, a user can select a range between from and to dates.
mat-date-range-input: MatDateRangeInput component is a form field to show a from date and to date selected by the user.
mat-date-range-picker: MatDateRangePicker component allows choosing the date range visually. See the figure below.
MatStartDate: A new directive to be used on input elements for start date in the range.
MatEndDate: A new directive to be used on input elements for end date in the range.
Consider the following code snippet that shows date range in the sample to-do application. Follow the link for a complete code sample.
<mat-form-field >
<!-- The date field label -->
<mat-label>Complete todo in the timeframe</mat-label>
<!-- Form field that shows from date and to date-->
<mat-date-range-input [rangePicker]="todoWindow">
<input matStartDate placeholder="Start date">
<input matEndDate placeholder="End date">
</mat-date-range-input>
<!-- a button that toggles date range picker -->
<mat-datepicker-toggle matSuffix [for]="todoWindow"></mat-datepicker-toggle>
<!-- date range picker allows selecting from and to date -->
<mat-date-range-picker #todoWindow></mat-date-range-picker>
</mat-form-field>
Figure 10: The new Date Range component in Angular Material
Other Miscellaneous Improvements
#7. Improvement in build time: We have seen an improvement in bundle size with Ivy. It also helps improve build times. Of course, it depends on various factors including application size, developer machine configuration. Angular documented its angular.io site build time improvement by 40%.
With Ivy, better build time means even the dev builds can use AoT. Using AoT is beneficial as it eliminates any differences with the production build.
#8. Improvement in Unit Test run time: TestBed, which configures unit testing environment in Angular, is revamped. It does not recompile all components between test runs resulting in improved unit test run time.
#9. Support for newer versions of TypeScript: Angular 10 supports TypeScript 3.9. Earlier, Angular 9 added support for TypeScript versions 3.6 and above .
Consider the following two interesting features in TypeScript 3.8
– ES Private fields: TypeScript allows creating private fields in a class with the access modifier private. ES has a private class field proposal in Stage-3. The field is prefixed with #. The field is scoped at class level. Consider the following example. Follow the link to read more on this topic.
class Todo {
#title: string
constructor(todoTitle: string) {
this.#title = todoTitle;
}
greet() {
// Works okay – private field used within the class
console.log(`The todo is ${this.#title}!`);
}
}
let newTodo = new Todo("Buy Milk");
newTodo.#title // error – can’t access private field outside the class
– Top-level await: We may use await with a promise to avoid using then function callbacks. However, the function using await need to be declared async. With top-level await, async can be applied at JavaScript module level. This eliminates the need to mark each function using await to be marked async.
#10. CLI to generate displayBlock components
By default, Angular components uses the CSS property display with the value inline. Component does not add a line break before or after the component.
Angular CLI in Angular 9.1.x (notice minor version 1) can generate the component with the CSS property display value block. The component will add a line break before and after the component.
Run the generate component command with the flag –displayBlock
ng g component todo-component --displayBlock
#11. Dependencies with CommonJS Imports
Angular 10 shows a warning if a project dependency uses CommonJS. ECMA Script Module System (ESM) is efficient. Given the time ESM is in use, JavaScript browser projects should move to a better and newer option. Considering CommonJS is built with serverside Node.js applications in mind, bundle size is not a priority. Tree shaking is inefficient. Hence, the bundle sizes are larger compared to ESM. Follow this link to read more on how CommonJS increases bundle size.
#12. Deprecated Support for older browsers
Angular 10 deprecated support for Internet Explorer mobile, Internet Explorer 10 and below.
#13. Using View Engine with an Angular 9 project
Ivy is the default compiler and runtime with Angular 9. To disable it and use View Engine, consider the following configuration. Change the field in tsconfig.json at the root of the project.
Figure 11: Configuration to toggle Ivy
Conclusion
Angular is evolving continuously. Angular 9 is a major release in the past few years. Ivy has been in the making and actively discussed in the Angular developer community for a while. The runtime and compiler improved the framework in multiple aspects. Angular 10 is another recent major version upgrade (in June 2020). Version 10 has relatively fewer updates ( as far as major version releases go).
At the beginning, the article introduced Angular versioning and significance of Angular 9. The article described how removing entry components simplified using imperative components. The article then discussed bundle size improvements with Ivy. Next, it discussed improved debugging with better API on the “ng” object.
The article also described strict mode with Angular CLI. It provided a sample implementation for Angular Material Date Range component.
The article also mentioned improved type checking in the component and directive template files, and discussed additional options with ProvideIn.
A JavaScript feature, ‘dynamic imports’ introduced with ES2020 has an implication on Angular 9 and Ivy. The ngc depends on the new dynamic imports as opposed to the old string syntax.
We concluded by showcasing the configuration to opt-out of Ivy and using View Engine after describing few miscellaneous Angular 9 and Ivy features.
Code Sample
Checkout code sample at the following Github repo. Clone, npm install and npm start to run the sample.
https://github.com/kvkirthy/todo-samples/tree/master/memoization-demo
This article was technically reviewed by Ravi Kiran and editorially reviewed by Suprotim Agarwal.
References
– Entry components documentation
– Bye bye entry components by Nishu Goel
– Dynamic Imports in JavaScript
– Christian Liebel’s blog – Angular & TypeScript: Writing Safer Code with strictNullChecks
– How to create private fields and functions in JavaScript class
– TypeScript 3.8
– Angular blogs
Angular 9
Angular 9.1
Angular 10
– Angular, deprecated APIs and features
This article was technically reviewed by Ravi Kiran.
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
V Keerti Kotaru is an author and a blogger. He has authored two books on Angular and Material Design. He was a Microsoft MVP (2016-2019) and a frequent contributor to the developer community. Subscribe to V Keerti Kotaru's thoughts at his
Twitter account. Checkout his past blogs, books and contributions at
kvkirthy.github.io/showcase.