Stay updated

Let's take a look at the current state of Angular
Angular: present and future
Monday, March 28, 2022

It’s been awhile since the last news article about the framework, so let’s get back to talking about Angular . According to surveys conducted by Stack Overflow, Angular remains the second most popular front-end framework coming in behind React, although the gap has grown compared to 2020. Another curiosity is that it does not seem particularly loved by its users (in fact it’s ranked fourth). 

It seems that it’s stability, instead of increasing its use, produces a dwindling enthusiasm: as if a complete framework, but too “opinionated”, is no longer enough. It is a paradox that is pushing the Angular team to reconsider some of their past choices, as we will see in the final paragraph. In the meantime, let’s see what happened in 2021.  

During 2021, two major versions were released (v.12 and v.13). First of all, the transition period, which started with the publication of version 9 where Ivy was inserted for the new compilation and rendering pipeline, has ended. The previous option, known as the View Engine, has been deprecated since version 12 (without any needed intervention in the code) although the libraries dependent on it have continued to work thanks to a special compiler called ngcc. As of version 13, however, View Engine is no longer available.   

It took years to complete Ivy and the results are evident even in the case of small applications: Angular has become simpler, faster and easier to maintain thanks to type checking, build optimizations and fast change detection (which we talked about here). 

Angular Package Format 

Changes have been made to Angular Package Format (APF). What is it? It is a specification for the structure and format of npm packages that is used primarily by native libraries (for example @angular/core or @angular/material) but also by third-party libraries. In the rough and tumble JavaScript world, developers consume packages in many different ways: some use SystemJS, others WebPack, or they might consume packages in Node or perhaps in the browser as UMD bundles, or through global access variables. This proliferation is due to the fact that for a long time JavaScript did not have an official way of importing/exporting code modules. 

APF supports all commonly used development tools and workflows with an emphasis on optimizations (smaller application sizes and shorter build times). At this address you can find the specifications, while in the following image you can find an excerpt of the @angular/core package. 

Angular Dev Tools

A browser extension is available on the Chrome web store that gives Angular developers new tools for both debugging and profiling applications. After installation, a tab called Angular becomes available in Chrome Dev Tools. 

The extension also has two additional tabs: Components and Profiler. The first allows you to explore the components and directives, to see a preview of them or change their status. The second offers a look at the execution of Angular change detection.  

In the image, you can see a sequence of bars, each of which symbolizes the cycles of change detection. The higher a bar, the longer the time spent in that cycle. Each bar has a detail that also shows the parental hierarchy of the selected directives.  

Testing in Angular

Protractor is a framework for end-to-end testing in Angular applications. It’s future is uncertain and as of version 12 it is no longer included in the new projects. The idea is to provide support for third-party solutions such as Cypress, WebdriverIO and TestCafe.

Remaining in the field of testing, we recall that Angular offers Jasmine in its projects, a JavaScript framework for writing and executing unit and integration tests. There is an official and comprehensive guide on how the Angular team thinks components, modules, services, pipes and directives should be tested. We also refer you to an article by Adolfo for an introductory discussion on the subject.  

Version 13 of Angular introduces improvements to the TestBed class that impact memory consumption and the speed of execution of each test performed. The detail is described in the following series of articles.  

Nullish Coalescing 

The ?? operator, which has long been used by TypeScript developers, has also been made available in Angular templates since version 12. So while up to now it had been necessary to write code like the following in templates:  

{{age !== null && age !== undefined ? age : calculateAge() }} 

now it is possible to write like so (clearly an advantage )  

{{ age ?? calculateAge() }} 

Dynamic creation of components

Ivy also benefits developers when writing code. Starting from version 13, the API for dynamically creating a component has been simplified (in this article I introduced the problem). ComponentFactoryResolver injection is no longer required, so a component can be instantiated with ViewContainerRef.createComponent without having to create an associated factory. So, with the new API, we can write for example: 

@Directive({ … }) 
export class MyDirective { 
    constructor(private viewContainerRef: ViewContainerRef) {} 
    createMyComponent() { 

Good-bye IE11 

IE11 has been permanently abandoned. The removal allows Angular not only to take advantage of the features of modern browsers (e.g. CSS variables and web animation) but also to produce smaller and faster applications due to the removal of Internet Explorer-specific polyfills. 

ng CLI 

The ng build command, starting from version 12, works by default on production. In addition, the CLI has enabled strict mode by default, which allows you to discover errors starting at the earliest stages of development. Here you will find the details about this mode.

The language service has also been moved to default to an Ivy-based one. What is it? We are talking about the service used by editors and IDEs for error checking and self-completion of instructions. The CLI now supports the use of a persistent build cache. Thanks to it you have a 68% improvement in build speed. This configuration (described in detail here) is inserted within the angular.json file 

    "$schema": "...", 
    "cli": { 
        "cache": { 
            "enabled": true, 
            "path": ".cache", 
            "environment": "all" 

Updating dependencies

When we create a new app with the ng new command we now use version 7.4 of RxJS.  

The JavaScript responsive extensions library is used pretty much everywhere in Angular and so we’re talking about an absolutely fundamental dependency. 

RxJs 7 is smaller than RxJs 6: so we go from 52 KB to only 19KB. An important refactor of the code has been made.  

The toPromise operator has been deprecated and will be completely removed in version 8. In it’s place, firstValueFrom() and lastValueFrom() were introduced. The firstValueFrom() operator resolves the promise on the first value of an observable before executing the unsubscribe. The lastValueFrom operator, on the other hand, waits for the last value before resolving the promise. So while in the past we had this

const numbers$ = of(1,2,3,4,5) 
// toPromise() will return the last value of the observable 
numbers$.toPromise().then(n => console.log("toPromise(): " + n)) 

now we can choose between  

// lastValueFrom() will return the last value just like to promise 
lastValueFrom(numbers$).then(n => console.log("lastValueFrom(): " + n)) 

 // firstValueFrom() will return the first value of the observable 
firstValueFrom(numbers$).then(n => console.log("firstValueFrom(): " + n))  

Beware that several operators have been renamed (e.g. zip has become zipWith), others deprecated and new additions have been made. Here you will find the detail.  

And the future? 

There are two main requests made by users and that are being processed by the Angular team. The official roadmap is available at the following address

The first is that of the Strictly Typed Reactive Form (here you will find the official RFC).

Take, for example, a form, populated with a default value. 

const partyForm = new FormGroup({ 
  address: new FormGroup({
                  house: new FormControl(1234), 
                  street: new FormControl('Powell St')}), 
                  formal: new FormControl(false), 
                  foodOptions: new FormArray([]) 

When we try to interact with the form and read its elements, we frequently find ourselves having ‘any’  value types. 

const partyDetails = partyForm.getRawValue(); // type `any` 
const where = partyForm.get('address.street')!.value; // type `any` 
partyForm.controls.formal.setValue(true); // param has type `any` 

Let’s imagine that we have a corresponding type: 

type Party = { 
  address: { 
      house: number,   
      street: string, 
  formal: boolean, 
  foodOptions: Array<{ 
    food: string, 
    price: number, 

With the proposal soon to be be published we will have the elements of the form completely typed. For example:  

const partyDetails = partyForm.getRawValue(); // a `Party` object 
const where = partyForm.get('address.street')!.value; // type `string` 
partyForm.controls.formal.setValue(true); // param has type `boolean` 

The second request is more radical (here you can find the detail): make the modules optional. 

NgModules are the basic concept of an Angular application. Even a Hello World app needs one to run. Modules are the reuse unit, libraries are modules, lazy-loading is based on modules (here Adolfo talks about it). 

Earlier, however, we talked about the dynamic creation of a component instance. This feature is full of pitfalls and it is not a given that the runtime works correctly. A component can expect  that upon its  constructor’s invocation, a service will be passed on. Typically it is a module that ensures that this happens correctly but if I directly install a component we risk not having the necessary provider at runtime. So, if you think about it (and it’s the only example in the web framework scene), components need modules that are therefore the smallest block of reusable code. 

In the next versions of Angular we will be able to choose whether or not to use NgModules. A standalone component (or pipe or directive) will not be declared in any module and will independently manage its dependencies and can be used directly without the need for an intermediate NgModule. Here’s a simple example: 

import {Component} from '@angular/core'; 
  standalone: true,   
  template: `I'm a standalone component!` 
export class HelloStandaloneComponent {} 

How will we manage dependencies? An imports property will be added inside the decorator @Component where we will specify the dependencies present in the template:

import {Component} from '@angular/core'; 
import {FooComponent, BarDirective, BazPipe} from './template-deps'; 

  standalone: true, 
  imports: [FooComponent, BarDirective, BazPipe], 
  template: ` 
    <div bar>{{expr | baz}}</div> 
export class ExampleStandaloneComponent {} 


The Angular team has therefore accepted the challenge of trying to provide, to those who want to use it, an alternative way to what has been seen so far.  Meanwhile, TypeScript and RxJS continue to make it an extremely solid framework for developing front-end solutions. These are the only essential dependencies of the framework and this means that development teams do not accumulate technical debt by following third-party libraries even for common problems such as managing forms or HTTP calls. TypeScript is now also used in the React ecosystem. RxJS, on the other hand, remains the most difficult theoretical obstacle to overcome for a team that starts using Angular, but, in my opinion, it is the real added value of this framework. 

See you at the next article!