Angular Release Schedule

Angular is constantly evolving. A quick look at the release notes of the framework shows that new releases are happening every week. For example, yesterday, we mentioned the latest updates of Angular 15.1.

Let’s talk about how often Angular is released. The main release cadence is the following:

  • Major version every six months (Angular 16 is released six months after Angular 15)
  • Minor versions every month if needed, usually 1 to 3 between each major version (Angular 15.2 is released a month after 15.1)
  • Patch versions every week if needed (Angular 15.1.1 is released the week after 15.1.0)

This is important because you can plan your upgrades based on that cadence. For instance, some of my consulting clients plan the major releases of their applications twice a year, one month after they get a new version of Angular.

It’s also important to know that major versions are supported for 18 months. This is for critical fixes and security patches only. New features and improvements are added to a major version during its six months lifespan.

As of today, here are the actively supported versions:

If you’re using any version older than 13, you’re out of the support window and potentially exposed to bugs, vulnerabilities, and other issues. As a result, it’s always recommended to use the latest major version as much as possible or as a plan B to stay one or two major versions behind, but not more.

You can read the entire rationale behind that approach as well as more information about Angular’s release schedule here: https://angular.io/guide/releases

ngrxLet: A better version of the async pipe

Yesterday, we mentioned how the async pipe can be used with *ngIf or *ngFor in our templates to declare a local variable that allows us to have multiple expressions using the same data:

<div *ngIf="user$ | async as user">
   <p>First name: {{ user.firstName }}</p>
   <p>Last name: {{ user.lastName }}</p>
</div>Code language: HTML, XML (xml)

While the above code works perfectly well, it’s not always convenient to add an additional *ngIf or *ngFor in our templates. Another shortcoming of the async pipe is that it doesn’t let us know if the observable has an error or completes successfully.

This is where the ngrxLet directive can save the day, as it solves all of the above shortcomings with a straightforward syntax. Our previous example becomes:

<div *ngrxLet="user$ as user">
   <p>First name: {{ user.firstName }}</p>
   <p>Last name: {{ user.lastName }}</p>
</div>Code language: HTML, XML (xml)

And if we want to get any errors or the completion status of the observable, we can do so with more local variables exposed by ngrxLet:

<div *ngrxLet="user$ as user; error as e; complete as c">Code language: HTML, XML (xml)

You can find a complete working example here. ngrxLet can be installed as a dependency using npm (npm install @ngrx/component), and it’s important to note that it is not the entire ngrx state management library, just a tiny subset of it, so using that directive does not require using anything else from ngrx.

Here is a link to a slightly expanded version of that tutorial with more information if you want to dig deeper into it: ngrxLet – A better version of the async pipe.

Async pipe syntax tricks

Yesterday, we wrote about how to use the async pipe to automatically subscribe and unsubscribe from our observables.

When I teach that topic, people usually have at least one of these two objections:

What if I also need the data from that subscription in my Typescript code?

At first, using the async pipe seems only to give you access to the data in your HTML templates. That isn’t the case, though, because you can still use the tap operator to “spy” on your observable and get the data from there. For instance (complete example here):

this.name$ = nameService.getName().pipe(
    tap(name => this.name = name)
);Code language: TypeScript (typescript)

And then in the HTML template:

<p>Name from async pipe: {{ name$ | async }}</p>Code language: HTML, XML (xml)

What if I need to read multiple properties from the object in that subscription?

Another way to put it is that you don’t want to end up doing something like this:

<p>First name: {{ (user$ | async)?.firstName }}</p>
<p>Last name: {{ (user$ | async)?.lastName }}</p>Code language: HTML, XML (xml)

The above code is pretty hard to read and requires one subscription for each property. This alone can be a disaster, as each subscription might trigger an HTTP request for the same data from the server!

Instead, you can do something like this, which uses only one subscription, stores the result in a local variable, then renders the data when it’s available. This technique works with any structural directive, such as *ngIf or *ngFor:

<div *ngIf="user$ | async as user">
   <p>First name: {{ user.firstName }}</p>
   <p>Last name: {{ user.lastName }}</p>
</div>Code language: HTML, XML (xml)

If changing the DOM structure by adding an element to accommodate that subscription bothers you, then you can use ng-template instead, though the syntax here can be a little bit unsettling, too:

<ng-template [ngIf]="user$ | async" let-user>
   <p>First name: {{ user.firstName }}</p>
   <p>Last name: {{ user.lastName }}</p>
</ng-template>Code language: HTML, XML (xml)

Ok, that’s probably plenty enough for today. Tomorrow, we’ll see how we can do even better than this.

How to avoid memory leaks with RxJs observables?

The easiest way to get in trouble in a big Angular application is to create a memory leak by not unsubscribing from your observables. While there are different techniques to unsubscribe your observables automatically, one is more concise, elegant, and overall the most error-proof.

That technique is to use the async pipe from the Angular framework.

Why is the async pipe such a great tool?

  1. First, it automatically subscribes to the observable, so we no longer need to call .subscribe().
  2. It returns the data from that observable, triggering Angular’s change detection when needed for our component to display the latest data.
  3. Finally, it automatically unsubscribes from the observable when our component is destroyed.

All of that with just 6 characters! (ok, perhaps a bit more if you want to count the whitespace):

<div>{{myObservable | async}}</div>Code language: HTML, XML (xml)

The async pipe works exactly like the code we would write (and thus duplicate over and over again, making our code base larger and thus our code slower) if we didn’t use it.

Check its source code here, and you’ll see that all it does is implement ngOnDestroy to unsubscribe from our observable.

There isn’t any good reason not to use the async pipe, and if you think you have some, stay tuned for our next messages, as we’ll cover some nice tips and tricks around using that pipe.

How to generate documentation for Angular applications?

Documenting software is hard. Not only that, maintaining software documentation is even more complicated and often forgotten.

What’s the solution, then? What about using an automated solution that:

  1. Generates documentation from code comments and does not require a Wiki or any third-party software.
  2. Generates said documentation automatically and can be part of your build process.
  3. Gives metrics and feedback to developers to encourage them to write more documentation.

Such a solution exists. It’s called Compodoc. Compodoc can generate a Javadoc-like website from all the comments written in your application (you can see an example of such documentation here):

Compodoc can be installed globally with npm:

npm install -g @compodoc/compodocCode language: CSS (css)

Or you can add it locally to a single Angular project by running the ng add schematic in your project folder:

ng add @compodoc/compodocCode language: CSS (css)

Then you can create a config file to decide which files to include in the documentation (for instance, you might want to exclude test, and Compodoc is ready to run with a single command:

npx compodoc -p tsconfig.doc.jsonCode language: CSS (css)

The above command creates a static HTML website documenting your entire application with all modules/components/pipes/directives/services.

My favorite feature is the documentation coverage statistics that show which parts of the application are well-documented and which are not, using a report similar to test coverage reports that developers are familiar with.

Formatting functions in Angular

We mentioned the default config options for the date pipe in Angular yesterday.

Did you know we can also format dates in our Typescript code using a formatDate function?

This function has the same signature as the date pipe, which makes perfect sense because… That’s the function used by the pipe itself (source code here):

formatDate(value: string | number | Date, 
           format: string, 
           locale: string, 
           timezone?: string): stringCode language: JavaScript (javascript)

All you need to use that function is to import it from @angular/common:

import {formatDate} from "@angular/common";Code language: JavaScript (javascript)

The only downside of that function is that there is no default format or locale, so we have to pass those two values as parameters, which isn’t the case for the date pipe.

And by the way, similar functions are available for numbers, currencies, and percentages:

For more information on those functions, I have this tutorial on formatting dates and numbers with Angular.

Date pipe default format and timezone

The date pipe is the most convenient way to format dates with Angular. However, very often, we need to use a consistent date format throughout our application, which means that we have to pass that custom format every time we use the date pipe:

<span>Today is {{today | date: 'MM/dd/yy'}}</span>Code language: HTML, XML (xml)

Of course, we could store that format in a constant and reuse that constant every time we use the pipe, but that’s not very convenient.

Luckily for us, since Angular 15, we can now set a default date format (and timezone) by configuring a new injection token called DATE_PIPE_DEFAULT_OPTIONS.

It works by adding the following code to your dependency injection config (array of providers) in app.modules.ts:

providers: [
  {
    provide: DATE_PIPE_DEFAULT_OPTIONS, useValue: {dateFormat: 'MM/dd/yy'}
  }
]Code language: JavaScript (javascript)

With such a config in place, we can use our pipe without any parameters and have our default formatting applied automatically in our entire application:

<span>Today is {{today | date}}</span>Code language: HTML, XML (xml)

The timezone can be customized as well with the timezone property of that same DatePipeConfig object.

The debugger keyword

Yesterday, we covered how to use the JSON pipe with a <pre> tag to debug JSON data on a web page.

Today, I want to cover one more debugging technique that is another time saver: The debugger keyword.

Whenever you want to add a breakpoint in your web application, add the Javascript instruction:

debugger;Code language: JavaScript (javascript)

Then open the dev tools in your browser and navigate to your application URL. Whenever Javascript hits that debugger statement, the runtime will stop on that breakpoint, allowing you to debug your code:

Once the browser is paused on that breakpoint, you can add other breakpoints by clicking on the line numbers in the browser dev tools, just like regular debuggers work.

Two important things to note:

  1. The breakpoint works only when the dev tools are open
  2. Don’t forget to remove the debugger statement once you’re done debugging. You probably don’t want to ship that one to production.

Debugging with the JSON pipe

We have all used console.log at some point to debug our code. With Angular, there is an interesting alternative to display debugging information on our web page temporarily: The JSON pipe.

The primary usage is as follows:

<span>myData | json</span>Code language: HTML, XML (xml)

The above code will output your data as a JSON string in the span element, but it won’t be formatted, so the JSON string can be hard to read:

{"affiliation":"friendly","symbol":"Default Land Unit","echelon":"none","mod1":"None","mod2":"None","uniqueDesignation":"","higherFormation":"","reinforcedReduced":"","flying":false,"activity":false,"installation":false,"taskForce":false,"commandPost":"None","tacticalMissionTasks":"None","type":"Land Unit"}Code language: JavaScript (javascript)

Instead, the following syntax works a lot better:

<pre>myData | json</pre>Code language: HTML, XML (xml)

The pre HTML tag stands for “preformatted” content. As a result, that tag will preserve any whitespace, new lines, and tabs, which makes reading that JSON data a lot easier:

{
 "affiliation":"friendly",
 "symbol":"Default Land Unit",
 "echelon":"none",
 "mod1":"None",
 "mod2":"None"
}Code language: JavaScript (javascript)

It’s a simple trick, yet a big time saver when debugging code that’s using complex JSON structures.

Exported Directives

Yesterday, we talked about Template Reference Variables. Today, I want to show you how a directive can be accessed with a Template Reference Variable.

You’ve probably seen that syntax before:

<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)" >Code language: HTML, XML (xml)

That syntax is possible because the NgForm directive is exported using the following syntax (actual Angular source code here):

@Directive({
   exportAs: 'ngForm'
})Code language: TypeScript (typescript)

The above code enables the usage of Template Reference Variables such as #myForm="ngForm" . This technique is widely used in Angular forms and component libraries to expose public directive properties (and methods) to your component’s template.

For instance, we can access myForm.value or myForm.valid in an expression.

ngModel is exported that way, too.