It’s pretty common in an Angular project to add the ability to “listen” for router events. That is, know that a user is about to (or already has) navigated to a new page. The most common reason is to push pageview events to analytics platforms (think Google Analytics or Azure Application Insights), but I’ve also used them to hook into whether a user is navigating away from a page (And stop them from losing their work), or to hide toaster/error messages if a user has moved away from a particular page.

In anycase, it’s actually fairly trivial to subscribe to router events.

The first thing to do is to inject the Router object into your service/component like so :

constructor(private router: Router)

Then to subscribe, we simply subscribe to a filtered list of navigation events like so :

this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe((event: NavigationEnd) => {
  //Do something with the NavigationEnd event object.
});

Notice that we are filtering only on NavigationEnd events, this is because the events stream from the router is *all* Router events. The main events you want to subscribe to are listed below (Although there are a couple more, I personally never really use them).

  • NavigationStart – Triggered when a navigation starts
  • NavigationEnd – Triggered when navigation ends successfully
  • NavigationError – Triggered when navigation ends with an error
  • NavigationCancel – Triggered when a navigation is cancelled (Often because a router guard returned false)
  • GuardsCheckStart – Triggered before guards are run as part of the routing
  • GuardsCheckEnd – Triggered at the end of guards running as part of the routing

The most important ones I’ve used are NavigationStart, to determine if a user is about to navigate away, and NavigationEnd when a user has successfully browsed to a new page. It’s also important to keep in mind NavigationError, as NavigationEnd will only trigger if a user was successfully able to visit a page, but you may be missing analytics of failed pages if you ignore NavigationError.

And that’s it! Now you can subscribe to all sorts of different router events with just a couple of lines of code!

Some forms require the ability to “clear” all input and “reset” the form. I struggled through a few different ways of clearing a form before I found a foolproof way that seemed to work in all scenarios I tested.

First, what didn’t work. NGForm does have two reset methods :

this.myForm.reset();

And

this.myForm.resetForm();

Both of these “appeared” to work, but I found it completely broke data binding at times where values got reset to null and lost their data binding. I personally use Template Driven Forms rather than Reactive Forms, so it may work in different scenarios, but for me, this really broke data binding.

If you use Template Driven Forms like me, then the best way I found to actually wipe values in the form was to first reset the underlying two way data binding object. E.g. If I’m binding to a “Person” object then I first do new Person() etc.

Then I can run the following code which only seems to reset the validity of controls rather than fiddling with the underlying data:

Object.keys(this.myForm.controls).forEach((key) => {
    const control = this.myForm.controls[key];
    control.markAsPristine();
    control.markAsUntouched();
});

This runs through every control and resets the validity without affecting binding. This seemed to work the best for me. An alternative I found would be to change the call to setErrors()

Object.keys(this.myForm.controls).forEach((key) => {
    const control = this.myForm.controls[key];
    control.setErrors(null);
});

Again, the first iteration worked for me, but try both if it doesn’t for you.

Adding An NGForm Extension Method

Now rather than copy and pasting this everywhere, instead I created an extension. I created a file called ng-form.extensions.ts with the following content :

import { NgForm } from '@angular/forms';

declare module "@angular/forms/" {
    interface NgForm {
      resetValidation(this:Form) : void;
    }
}

NgForm.prototype.resetValidation = function(this:NgForm) {
    Object.keys(this.controls).forEach((key) => {
        const control = this.controls[key];
        control.markAsPristine();
        control.markAsUntouched();
    });
}

Then in my component, I have to import this extension file like so :

import 'src/app/_core/extensions/ng-form.extensions'

And I then simply reset the form like so :

this.myForm.resetValidation();

Much cleaner!

One of the more frustrating limitations of vanilla JavaScript is that there is actually no GUID or UUID generator in the language. That’s right, out of the box, you cannot generate a GUID with a nice single line of code! Very annoying.

Luckily, there are two ways that I’ve used in the past to generate GUID or GUID-like strings.

This first piece of code is one I use in places where the randomness isn’t such a big deal. It might be just generating correlation ids, or just as a way to generate some randomized letters/numbers, but not global uniqueness and/or collisions aren’t such a big deal.

generateGuid() : string {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random() * 16 | 0,
      v = c == 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

In most cases where I’m generating a GUID on the front end, I’m not worried too much about how secure things are. You shouldn’t be too concerned on collisions in the browser anyway because a user could just as easily inject JavaScript and/or modify an API call that uses the GUID into using their own string.

However, for a more secure GUID, there is obviously an NPM package for that!

npm install uuid

Then use the uuidv4 function to generate guids as you need them!

import { v4 as uuidv4 } from 'uuid';
let myGuid = uuidv4();

Again, in most cases I just use the first function. But I know people come up with all sorts of links on how “Math.random()” isn’t truly random etc. So both options are there!

An interesting question came up recently about the difference between the “optional” flag in Typescript, and setting something as null. More importantly, it was a question of whether the following were synonymous :

export class MyClass {
  myProperty? : string;
}
export class MyClass {
  myProperty : string | null;
}

The answer is no, these are not the same thing, but it took some explaining to do to people from backgrounds that do not have a “optional” flag, and instead just use a nullable type. For instance, in C#, we may do something like so :

class MyClass 
{
    public string? MyProperty { get; set;}
}

This tells the compiler/runtime that MyProperty is nullable, and by default, will have a null value if no value is given. However in Typescript, the question mark operator is *not* a nullable operator, it instead denotes whether something is “optional”. And there’s an important difference.

export class MyClass {
  myProperty? : string;
}

This says that the MyProperty is optional, and if no value is given, that the value will be set to “undefined”. It’s an important distinction because it’s not a “default” value, it’s “no value”. This is important because if you initialize the class like so :

let class : MyClass = { };

No error will be thrown because the property is optional.

When you instead do something like so :

export class MyClass {
  myProperty : string | null;
}

And then we initialize it the same way :

let class : MyClass = { };

We get the following error :

Property 'myProperty' is missing in type '{}' but required in type 'MyClass'

This is because while we are allowing null to be set as the value, it does not change whether a value needs to be set or not. It’s not optional. Therefore, if we use the discriminated union, we must pass in null as the initial value like so :

let class : MyClass = { myProperty : null };

Again, the most important thing about all of this is divorcing the idea that the question mark operator works the same as it does in C#. It is not a signifier of whether something can be null, it is instead used to mark something as optional. And that is an important difference.

When binding a dropdown/select list in Angular, you will come across two different ways of databinding, using [value] and using [ngValue]. They actually have a very simple difference. But let’s whip up an example first.

Imagine I have a component that holds a list of books :

export class AppComponent  {
  selectedBook : any;
  myBooks = [
    { id : 1, title : "War and Peace", author : "Leo Tolstoy" }, 
    { id : 2, title : "The Lord of the Rings", author : "J. R. R. Tolkien" }, 
    { id : 3, title : "Pride and Prejudice", author : "Jane Austen" }, 
  ];
}

Then in my view I have nothing but a dropdown, and I’m binding to the myBooks list. Also note that I’m using ngModel on the actual select to capture what is selected. And in this example, we are using the [value] attribute.

<select [(ngModel)]="selectedBook">
    <option *ngFor="let book of myBooks" [value]="book.id">{{book.title}}</option>
</select>
<br /><br />
The selected book is : {{selectedBook | json}}

At the end, I’m outputting my selected book in JSON format, just so we have some feedback on what we are selecting.

When I run this, everything works. When I select a book, I see the following :

Notice one thing however. Our “2” which is the id of our book is wrapped in quotes. This is the first thing you’ll notice about using [value]. [value] always binds as a string. Even if you pass it a number type, it will be coerced into a string.

You may not think this is a big deal at first. But if you are fully immersed in Typescripts strict typing, then this can cause unintended consequences because you may end up comparing strings and numbers (Or really any other type) when you never intended to.

That’s where [ngValue] comes in. Let’s change our binding to use [ngValue].

<select [(ngModel)]="selectedBook">
    <option *ngFor="let book of myBooks" [ngValue]="book.id">{{book.title}}</option>
</select>
<br /><br />
The selected book is : {{selectedBook | json}}

Now when we view our example in the browser :

No more quotes! This is because [ngValue] will bind any type and never try and convert things to strings.

Now obviously we are binding the id in our example. But often what happens is that you will require additional info about that item. So you end up querying the initial list to get say the title of the book. Ugh!

But remember, [ngValue] can bind keeping the original type in tact. So we can simply change our binding to be the entire book object.

<select [(ngModel)]="selectedBook">
    <option *ngFor="let book of myBooks" [ngValue]="book">{{book.title}}</option>
</select>
<br /><br />
The selected book is : {{selectedBook | json}}

Now, instead of just returning our id. Our selectedBook is the entire book object!

One final piece of the puzzle is that [value] will output HTML to the browser with the value intact like so :

<option value="1">War and Peace</option>

However if you use [ngValue], you instead get :

<option value="0: Object">War and Peace</option>

Because the binding is on an object. While this may not seem like a big deal (Who’s reading your HTML anyway?), it may be an issue if you use a browser automation tool such as selenium or cypress that is required to read the value of each option. So just keep that in mind!

In Summary :

  • Use [value] when you are binding to a string value and only a string value. Or you need access to the option value inside the HTML for automation purposes
  • Use [ngValue] when you are binding to any type and/or you want the entire option bound instead of just a string

I came across an interesting problem recently where I had to check if a date was before or after today. Getting todays date seemed trivial :

let today = new Date();

But in my test cases, things were blowing up, often at weird times of the day. And it occurred to me that I wasn’t just comparing dates, I was comparing the times on those date objects too!

Such is Javascript, there isn’t actually a way to ask a date object for *only* the date portion for comparisons sake, it always has a time component attached. So for example if I have something like so :

let someDate = someService.getTheDate();// Returns Sat Jan 16 2021 08:30:00
let today = new Date();// Returns Sat Jan 16 2021 9:30:00
let isSameDay = today == someDate; // False!

It’s comparing the time as well as the date!

A very very common pitfall is assuming that the method .getDate() on a Date object will return the date.. Well.. It does, but only the day of the month. So in our example, it will return 16 as in the 16th of Jan. But obviously if you are comparing dates across different months, this isn’t going to work!

So how can we compare just the dates? There is some.. shall we say… interesting fixes out there. One that seems the most prominent is to zero out the time portion :

let today = new Date();// Returns Sat Jan 16 2021 9:30:00
today.setHours(0, 0, 0, 0); // Today is now Sat Jan 16 2021 0:00:00

But the issue with this method is that your date object now has a zero’d out time so if you want to use it elsewhere, you should first clone the date object, then zero it out, then compare it. Something like so :

let today = new Date();// Returns Sat Jan 16 2021 9:30:00
let clonedDate = new Date(today);
clonedDate.setHours(0, 0, 0, 0); // Today is now Sat Jan 16 2021 0:00:00
console.log(today);// Still returns Sat Jan 16 2021 9:30:00

However, this setHours method didn’t sit well with me. It was somewhat ambiguous what it was doing, even with the cloning. So my prefered approach was actually to create a new date object using only the parts I cared about.

let today = new Date();// Returns Sat Jan 16 2021 9:30:00
let clonedDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());

Then I can compare clonedDate to another date that we create using only the date portion, and the comparison works perfect!

One of the most infuriating parts of a new project setup is the npm install. A new Angular project from the CLI (Running “ng new”) can even take several minutes. And even if it’s an existing project that you know you have already setup, but you just want to check, a simple npm install can still take 30 seconds just to say “Yep all good here!”.

An option you see get thrown around often is to switch to using Yarn. Using Yarn from the command line is very similar to NPM (Infact we have a NPM vs Yarn Cheatsheet right here!), but what you’ll quickly find is that Yarn is so much more performant. The biggest reason is that Yarn has an offline global cache on your computer so repeated installs of the same package (For example, creating new Angular projects over and over again), will simply utilize the cached version rather than downloading the package all over again over the internet. Sounds good to me!

Adding Yarn after the fact to an existing project may be relatively straight forward. But what we are actually looking for is the ability to use Yarn with the actual internal angular cli when it tries to install a package.

Using Yarn Globally

If you want to use Yarn globally for *all* Angular projects on your machine, then all you need to do is run :

ng config -g cli.packageManager yarn

This updates the .angular-config.json inside C:\Users\YourUser on Windows to look like so :

{
  "version": 1,
  "cli": {
    "analytics": false,
    "packageManager": "yarn"
  }
}

Using Yarn On A Single Project

Sometimes you don’t want to globally use Yarn, and you just want to set it up on a new project you are about to create. This can be a bit of a headache as the initial call to ng new is the the most painful part of the entire process as it will use npm to install all the base packages, even if once the project is setup you switch to Yarn.

But we have a bit of a cheatcode to get around it!

When creating our project we can run :

ng new --skip-install

Where the skip install flag will actually skip over the final npm install after creating the project. From there, we can run the following command *from inside the project* :

ng config cli.packageManager yarn

Notice how we don’t have the -g flag like before. This sets up yarn as the package manager for this project only. From there, we just run

yarn

And the initial install of Angular components will happen like they normally would on an ng new command, but using Yarn instead.

While many API’s allow you to upload files via multi-part POST forms, others prefer to stick with a pure JSON approach and accept uploads in base64 format allowing you to always be sending and receiving JSON. This means that if a user selects a file in your Angular app, you need to be able to convert that file to Base64 before sending it on.

I thought this would be a rather trivial task but there seems to be some really complicated ways to do what seemed simple at first. Many examples tried to use async/await and promises, but Angular really prefers observables. Ontop of that, people were using an API that was not actually about returning base64 strings, but returning DataURI’s which are very close, but some browsers return the result as data:base64here rather than just the base64.

Anyway! The actual code looks like this. In my view I have :

<input type="file" (change)="onFileSelected($event)" />
<br /><br />
base64 Output : <br />
{{base64Output}}

And in my code behind I have :

export class AppComponent  {
  base64Output : string;

  onFileSelected(event) {
    this.convertFile(event.target.files[0]).subscribe(base64 => {
      this.base64Output = base64;
    });
  }

  convertFile(file : File) : Observable<string> {
    const result = new ReplaySubject<string>(1);
    const reader = new FileReader();
    reader.readAsBinaryString(file);
    reader.onload = (event) => result.next(btoa(event.target.result.toString()));
    return result;
  }
}

Notice a few things about the code.

  1. FileReader is event driven. e.g. You can’t say “Load this file” and then immediately get the result. This means that we either have to use promises or observables, because we are using Angular, let’s use observables.
  2. We use a ReplaySubject because we only need to calculate the file once. e.g. If we subscribed multiple times to the same return subject of this method, it doesn’t need to recalculate the base64 since it’s deterministic (The same file is always the same Base64 string).
  3. I saw some guides saying to use reader.readAsDataURL(file), but again this had weird issues in some browsers. It’s better to load the file as per normal, then use the btoa function to actually return Base64 without any other gunk in the response.

Hopefully that makes sense!

Take, First, and Single all appear to be almost identical in RxJS/Angular at first glance. But actually, they have some very important differences that could throw up some very weird errors if you aren’t expecting them. If you have spent any time working with C# LINQ expressions at all, you may actually find a bunch of this familiar.

In anycase, let’s jump right in.

Take(1)

Take(1) is the easiest of the three. It simply takes the first value output by the observable, then unsubscribes itself. As an example :

let myObservable = new Subject();

let subscription = myObservable.pipe(take(1)).subscribe(x => {
  //Do something with the data. 
  console.log(x);
});

myObservable.next("Foo");
myObservable.complete();

console.log(subscription.closed);

The output of this would be :

Foo
True

As we subscribed, output the value, then the subscription is closed. However consider the following :

let myObservable = new Subject();

let subscription = myObservable.pipe(take(1)).subscribe(x => {
  //Do something with the data. 
  console.log(x);
});

myObservable.complete();

console.log(subscription.closed);

Notice how we don’t call next on our observable at all. Well the output of this is still :

True

As we still abide by the observable being completed regardless of whether we got any value from it. Also consider the following :

let myObservable = new Subject();

let subscription = myObservable.pipe(take(1)).subscribe(x => {
  //Do something with the data. 
  console.log(x);
});

myObservable.next("Foo");
myObservable.next("Bar");
myObservable.complete();

console.log(subscription.closed);

This still outputs

Foo
True

Because we are using take(1). We are unsubscribing from the observable so any additional values are not pumped to the subscription.

First()

Now consider the following with First() :

let myObservable = new Subject();

let subscription = myObservable.pipe(first()).subscribe(x => {
  //Do something with the data. 
  console.log(x);
});

myObservable.next("Foo");
myObservable.complete();

console.log(subscription.closed);

This outputs the same as earlier.

Foo
True

But consider the following when we don’t call next on our observable :

let myObservable = new Subject();

let subscription = myObservable.pipe(first()).subscribe(x => {
  //Do something with the data. 
  console.log(x);
});

myObservable.complete();

console.log(subscription.closed);

We actually get :

Foo
ERROR : no elements in sequence - EmptyError

Why? Because we closed off our observable before even the first value was output. This may seem like an actual worse feature to have, but it’s an important distinction. If you are always expecting at least one value, then you may use first() to log errors when you don’t get any data. It’s almost signalling the intent of the code that there should always be atleast one value coming from the observable.

Finally, also consider the following code :

let myObservable = new Subject();

let subscription = myObservable.pipe(first(x => x == "Bar")).subscribe(x => {
  //Do something with the data. 
  console.log(x);
});

myObservable.next("Foo");
myObservable.next("Bar");
myObservable.complete();

console.log(subscription.closed);

Notice how we can pass a matching function to our first operator to tell us to only match on a certain value. This is an added piece of functionality that take(1) cannot do on it’s own!

Single()

Single is very similar to using First() in some ways, with an added restriction. Consider the following :

let myObservable = new Subject();

let subscription = myObservable.pipe(single()).subscribe(x => {
  //Do something with the data. 
  console.log(x);
});

myObservable.complete();

console.log(subscription.closed);

This also throws an error just like first() because we are completing the observable before any values are output. But also consider the following :

let myObservable = new Subject();

let subscription = myObservable.pipe(single()).subscribe(x => {
  //Do something with the data. 
  console.log(x);
});

myObservable.next("Foo");
myObservable.next("Bar");
myObservable.complete();

console.log(subscription.closed);

This results in a new error :

ERROR Sequence contains more than one element

While first() will simply take the first value and ignore all others, single() will take the first value but will throw an exception if there is more than 1 available. This is an important distinction because again, it signals the intent of the code that we are expecting 1, and only 1 value. If there is more than 1, then something as gone wrong and we should throw an exception.

A common pattern when working with observables/subjects inside an Angular Component, is to store the subscriptions in a list, and then unsubscribe when the component is destroyed.

Now I’ve seen many developers not bother unsubscribing at all when it comes to HttpClient requests, but it’s a good habit to get into as more often than not, you will get to a point where you are using Observables/Subjects for more than just simple API calls, and then you will really need to unsubscribe!

A common example of how many developers implement this is like so :

export class AppComponent implements OnInit, OnDestroy {

  subscriptions : Subscription[];

  constructor(private myService : MyService)
  {
  }

  ngOnInit() {
    let subscription = this.myService.getData().subscribe(x => {
      //Do something with the data. 
    });
    this.subscriptions.push(subscription);
  }

  ngOnDestroy() {
    this.subscriptions.forEach(x => {
      if(!x.closed) {
        x.unsubscribe();
      }
    });
  }
}

A better (just in my opinion) option is typically to use a simple boolean variable to close off all subscriptions when the component is destroyed. This is used in conjunction with the takeWhile operator of RxJS like so :

export class AppComponent implements OnInit, OnDestroy {
  isAlive : boolean = true;

  constructor(private myService : MyService)
  {
  }

  ngOnInit() {
    this.myService.getData().pipe(takeWhile(() => this.isAlive)).subscribe(x => {
      //Do something with the data. 
    });
  }

  ngOnDestroy() {
    this.isAlive = false;
  }
}

This is a better option in my opinion because you don’t need to keep a list in memory of subscriptions and there is slightly less boilerplate code going on. But still, we have to litter our components with this “isAlive” flag everywhere, and remember to add an ngOnDestroy that sets it to false. You could create base components that exposes this flag, but it’s still a bit of boilerplate that you could do without.

What we really are looking for is a nice library to do all of this for us. As it so happens, I found one called “TakeWhileAlive”. It’s NPM page is here : https://www.npmjs.com/package/take-while-alive. At first this worked great! That is, until I deployed it into production and started seeing weird happenings. As it turns out, it doesn’t work once you deploy the project in production mode : https://github.com/joostme/takeWhileAlive/issues/2 doh!

Luckily, that Github issue pointed me to another great library. “TakeUntilDestroy“. It works like this.

If Angular 8 or below :

npm install ngx-take-until-destroy --save

If Angular 9 or above then :

npm install @ngneat/until-destroy

Then inside your component, if you are using Angular 8, you only need to do the following :

import { untilDestroyed } from 'ngx-take-until-destroy';

this.myService.getData().pipe(untilDestroyed(this)).subscribe(x => {
  //Do something with the data. 
});

And that’s it. The one caveat is that you *must* have an empty ngOnDestroy method, even if it’s not being used. The library will throw an error if this is not the case. But otherwise, you will now auto unsubscribe without any additional boilerplate just by adding untilDestroyed onto all of your subscriptions.

Now for Angular 9+, things are a little more complicated, but still rather easy. The only additional logic you need is to add a single attribute onto your component like so :

@Component(...)
@UntilDestroy()
export class AppComponent implements OnDestroy {
 //...
}

Notice how we added UntilDestroy() onto our component. Then we still add untilDestroyed(this) onto our subscriptions similar to Angular 8, and we will auto unsubscribe when our component is destroyed.