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.

I’ve seen some diabolical ways Angular developers have tried to “subscribe to an observable.. but return that same observable”, or at least that’s how it was explained to me when I saw the following code :

getData() { 
  let observable = this.myService.getData();

  observable.subscribe(x => 
  {
    //do something with the data here
  });

  //Also return the observable here. 
  return observable;
}

This is very bad practice for a very simple reason. Each subscription to an observable, for the most part, will execute the observable method. Remember, observables are typically lazy loading and therefore execute only on a subscription. But they also execute *every* subscription.

In the above code, should someone subscribe to the observable returned from the method, it will also execute the underlying observable. If this is an API call for instance, you will end up calling the endpoint twice.

So what’s the right way to do this? It actually all depends on how getData() is being called, and what you need the data for *inside* the method.

If You Need Access To The Data You Will Then Return Anyway, Use Tap

We actually have a full article on how the Tap operator works right here. But if we take our above example, it would work a little like this :

getData() {
  return this.myService.getData().pipe(tap(x => 
  {
    //Do something with the data here. 
  }));
}

This works if you need access to the result (For example for caching), but you don’t intend to edit the result (For example map it to another type). And the caller to getData() should just get whatever the result from the service was.

If You Need To Modify The Result Before Returning, Use Map

This one is again pretty straight forward :

getData() {
  return this.myService.getData().pipe(map(x => 
  {
    return new MappedClass(x.value);
  }));
}

We use Map if we want to modify the result before returning it to the caller. It should be noted that again, if you don’t want to manipulate the result at all, then use Tap.

If The Caller Doesn’t Need The Result At All, And May Or May Not Subscribe, Use Replay Subject

This one might be a bit complicated, but here it is :

getData() {
  let subject = new ReplaySubject(1);

  this.myService.getData().subscribe(x => 
  {
    //Do something here. 
    subject.next();
    subject.complete();
  });

  return subject;
}

We create a ReplaySubject that has a buffer size of 1. (For why we use ReplaySubject here and not Subject, see here). Then then call the service, and on the completed subscription, complete the ReplaySubject, letting any callers know (If they care at all!) that we are done.

This has a couple of benefits :

  1. The call to the service is made regardless of whether this method is subscribed to or not. For example if you are calling this on button press (Where you don’t care about the result) versus calling it somewhere else in your component (Where you do care about the result), it doesn’t matter.
  2. The ReplaySubject is import as the call to myService might complete before a subscription is added to the returned subject.

I do want to point out that on the original subscription, you may need to unsubscribe/complete the observable returned from myService, but the point stands that a ReplaySubject can be a great way to let a caller subscribe “if they want”, but if they don’t things still run fine.

If The Caller Is Marked Async, Or You Prefer Promises, Then Use Promises

This is certainly not ideal. In most cases, you should try and stick with using Observables in an Angular application. But if you really need to, you can switch to promises *if you are sure there will be no negative side effects* . The most important being that you understand that how promises and observables can be very similar, but do have some distinct differences.

The code would look like so :

async getData() {
  let data = await this.myService.getData().toPromise();

  //do something with the data. 

  //return the data if we want. 
}

I recently was helping another developer understand the difference between Subject, ReplaySubject, and BehaviourSubject. And thought that the following examples explain the differences perfectly.

Subject

A subject is like a turbocharged observable. It can almost be thought of an event message pump in that everytime a value is emitted, all subscribers receive the same value. The same analogy can be used when thinking about “late subscribers”. A Subject does not have a memory, therefore when a subscriber joins, it only receives the messages from that point on (It doesn’t get backdated values).

So as an example :

let mySubject = new Subject<number>();

mySubject.subscribe(x => console.log("First Subscription : " + x));

mySubject.next(1);
mySubject.next(2);
mySubject.next(3);

mySubject.subscribe(x => console.log("Second Subscription : " + x));

mySubject.next(4);

This will output :

First Subscription : 1
First Subscription : 2
First Subscription : 3
First Subscription : 4
Second Subscription : 4

Pretty straight forward. The first 3 values were output from the subject before the second subscription, so it doesn’t get those, it only gets new values going forward. Whereas the first subscription, as it subscribed before the first values were output, gets everything.

Now for the most part, you’ll end up using Subjects for the majority of your work. But there can be issues when you have async code that you can’t be sure that all subscriptions have been added before a value is emitted. For example :

let mySubject = new Subject<number>();
myAsyncMethod(mySubject);
mySubject.subscribe(x => console.log("First Subscription : " + x));

Imagine that “myAsyncMethod” is an asynchronous method that calls an API and emits a value on the given subject. This method may or may not complete before the subscription is added and therefore in rare cases, the subject did output a value, but you weren’t subscribed in time. These sort of race conditions on subscribing is a big cause of headaches when using plain Subjects.

ReplaySubject

That’s where ReplaySubject comes in. Imagine the same code, but using a ReplaySubject :

let mySubject = new ReplaySubject<number>();

mySubject.subscribe(x => console.log("First Subscription : " + x));

mySubject.next(1);
mySubject.next(2);
mySubject.next(3);

mySubject.subscribe(x => console.log("Second Subscription : " + x));

mySubject.next(4);

This outputs :

First Subscription : 1
First Subscription : 2
First Subscription : 3
Second Subscription : 1
Second Subscription : 2
Second Subscription : 3
First Subscription : 4
Second Subscription : 4

Notice how we get the first 3 values output on the first subscription. Then immediately as the Second Subscription joins, it also outputs the first 3 values, even though when they were emitted, the second subscriber had not yet joined the party. Then going forward, both subscribers emit the 4th value.

So what’s going on here? It’s actually quite simple. A ReplaySubject remembers the previous X values output, and on any new subscription, immediately “replays” those values to the new subscription so they can catch up. I say previous “X” values because by default, a ReplaySubject will remember *all* previous values, but you can configure this to only remember so far back.

For example :

let mySubject = new ReplaySubject(2);

This will remember only the last 2 values, and replay these to any new subscribers. This can be an important performance impact as replaying a large amount of values could cause any new subscriptions to really lag the system (Not to mention constantly holding those values in memory).

Back to our problem async code with Subject. If we change it to a ReplaySubject :

let mySubject = new ReplaySubject<number>();
myAsyncMethod(mySubject);
mySubject.subscribe(x => console.log("First Subscription : " + x));

Then it actually doesn’t matter if myAsyncMethod finishes before the subscription is added as the value will always be replayed to the subscription. Pretty nifty!

BehaviorSubject

A BehaviorSubject can sometimes be thought of a type of ReplaySubject, but with additional functionality (Or limitations depending on how you look at it).

If you think of a BehaviorSubject as simply being a ReplaySubject with a buffersize of 1 (That is, they will only replay the last value), then you’re half way there to understanding BehaviorSubjects. The one large caveat is that BehaviourSubjects *require* an initial value to be emitted.

For example :

let mySubject = new BehaviorSubject<number>(1);

mySubject.subscribe(x => console.log("First Subscription : " + x));

mySubject.next(2);
mySubject.next(3);

mySubject.subscribe(x => console.log("Second Subscription : " + x));

mySubject.next(4);

This outputs :

First Subscription : 1
First Subscription : 2
First Subscription : 3
Second Subscription : 3
First Subscription : 4
Second Subscription : 4

So again, we have the ReplaySubject type functionality that when the second subscriber joins, it immediately outputs the last value of 3. But we also have to specify an initial value of 1 when creating the BehaviorSubject.

But why is an initial value important? Because you can also do things like so :

let mySubject = new BehaviorSubject<number>(1);
console.log(mySubject.value);

Notice we can just call mySubject.value and get the current value as a synchronize action. For this to work, we always need a value available, hence why an initial value is required. Again, if you don’t think that you can provide an initial output value, then you should use a ReplaySubject with a buffer size of 1 instead.

Also, just a quick warning on BehaviorSubjects, this might be one of those times where spelling trips you up if you are not American. For example if you are getting the warning :

Cannot find name 'BehaviourSubject'

Just remember it’s Behavior not Behaviour!

In a recent project, I’ve gotten into the habit of using the timer operator inside RxJS. At first I thought it was quite hacky, but actually.. It can come in incredible useful in scenarios that you may have previously used setTimeout. That might make it sound even worse! But let me explain.

In my particular case, I needed to load an Esri map on the page. If you’ve never heard of that before, just think of it as a Google Maps style widget. However, loading this widget could max out bandwidth on some connections as it tried to load many tiles (Images of the map) all at once. Because of the async nature of my application, I was also trying to load some important information to display side by side with the map. This information was far more important than loading the map fast, and yet, they were competing with each other for resources.

What I really wanted was just a small delay in loading the map to give a chance for other requests to go through first. This was somewhat hacky but actually worked well. My first iteration was simple with a timeout like so :

let mapLoader = setTimeout(() => this.loadMap(), 130);

//Somewhere in my ngDestroy
clearTimeout(mapLoader);

This worked actually just fine. But my main issue is that I’ve introduced a new paradigm for “unsubscribing” from observables, in this case we use the clearTimeout method to remove timeouts. What I wanted was a way to use RxJS, so that when I unsubscribe from all my other subscriptions, this simple timer is also unsubscribed.

And easy enough, RxJS has just the thing! Timer.

We can change our code to look like so :

import { timer } from 'rxjs';

let mapLoader = timer(130).subscribe(x => this.loadMap());

Simple! All this does is set a timer to go off in 130ms. Best of all, it returns a subscription just like any other Observable.

If we wanted to, we could also do something like so :

import { timer } from 'rxjs';

let mapLoader = timer(130, 130).subscribe(x => this.loadMap());

So run our loadMap() method in 130ms, and then run it again *every* 130ms after that. These numbers can be completely different, for example :

import { timer } from 'rxjs';

let mapLoader = timer(0, 130).subscribe(x => this.loadMap());

Run right now, and *then* run every 130ms etc.

While Timer might not be used in every project, it can come in incredibly handy as either a delay, or a much nicer way to have repeating timers without having to use recursive setTimeouts. And best of all, they fit with the existing paradigm of Observables/Subscriptions within Angular.

The use of TrackBy in my opinion is severely underrated in Angular. The performance benefits gained from using it can be huge (And very noticeable) for such a small code change. But before we dive too deep, let’s talk about how an NgFor loop works in Angular when you don’t use TrackBy at all.

Imagine a simple component with the following code behind :

export class AppComponent {
  employees : any[];

  resetEmployees() {
    this.employees = [
      {id : 1, name : 'John Smith'}, 
      {id : 2, name : 'Jane Smith'}, 
      {id : 3, name : 'Joe Bloggs'}, 
      {id : 4, name : 'Janey Blogs'}, 
      {id : 5, name : 'John Doe'}, 
      {id : 6, name : 'Jane Doe'}, 
    ];
  }
}

And a view that is also rather simple like so :

<button (click)="resetEmployees()">Reset</button>
<table>
  <tr *ngFor="let employee of employees">
    <td [attr.data-id]="employee.id">{{employee.name}}</td>
  </tr>
</table>

Now imagine a scenario like so :

  1. The page is loaded, no employees have been loaded, so the list is empty.
  2. We hit the reset button, and employees are set, and so the ngFor loop kicks off and draws them.
  3. We hit the reset button *again*. Employees are set, but it’s the same list! Doesn’t matter, ngFor loop kicks off and we re-draw them

It’s step 3 that is a problem. It’s an issue because drawing in the Dom is actually an expensive operation. Setting the list (even to the same list), means we remove all 6 items from the list, and then draw 6 items again.

So why?

The reason is that ngFor actually has a “default” trackBy. And it’s by object reference. Each time we set the list, because the actual reference has changed (Even the though the values have not), we redraw the entire table Dom again.

You can actually test this by viewing the elements in chrome dev tools. Each time you click reset, you’ll see the table light up like a xmas tree because it’s having to redraw everything.

Adding TrackBy

The first thing we need to do to add a TrackBy is to first identify a unique field on our array items. It actually doesn’t have to be a single field, but it should be some way to uniquely identify each record. In our case that’s easy, we can use the id field which is unique among all employees.

We then add a method that will take an item, and return the unique identifier.

getEmployeeId(index : number, employee : any) {
  return employee.id;
}

Then on our ngFor loop, we add the trackBy like so :

<table>
  <tr *ngFor="let employee of employees;trackBy:getEmployeeId">
    <td [attr.data-id]="employee.id">{{employee.name}}</td>
  </tr>
</table>

Note we don’t *call* getEmployeeId, we just pass the name of the method that we want to run to identify unique rows. Now when we run the reset method, and we watch it in Chrome Tools, we can see it no longer lights up as it’s not having to re-draw everything time and time again.

Where Is This Useful?

So the main question probably becomes, but where is this useful? You might think at first that you never do this sort of wholesale array setting. But in reality, you probably do. Imagine this code :

this.employeeService.getAll().subscribe(x => {
  this.employees = x;
});

It’s extremely common for API calls (Or really any rxJS subscription), to completely reset the value of an array with the results. If we didn’t use trackBy, and this ran often, we would end up redrawing a lot of elements that even if at first with a small number of results we didn’t notice, could quickly turn into a complete performance sink.

Other Notes On TrackBy

Trackby doesn’t suddenly make your code unresponsive. I’ve seen this crop up a little bit where people think if an item is set with the same id, then nothing about that item will update in the table, that’s not true.

For example if I created a method to change the name of an employee :

changeName() {
  this.employees[0].name = 'New Name';
}

And then drive it off a button click :

<button (click)="changeName()">Change Name</button>

The name is updated just fine. Trackby is about redrawing the overall list Dom, not the individual elements in it.

Same goes if we add an item like so :

addEmployee() {
  this.employees.push(
    {
      id : 7, 
      name : 'New Employee'
    }
  )
}

And trigger it from a button click. Again, it’s just as responsive with a trackBy than without.

This is such a simple error but one that catches me out on every single new project it seems. The full error is :

Error: StaticInjectorError[HttpClient]:
StaticInjectorError[HttpClient]:
NullInjectorError: No provider for HttpClient!

Unfortunately it’s not that descriptive, but it’s an easy fix.

In your app.module.ts, you need to import the HttpClientModule.

Simply add the import at the top of the file :

import { HttpClientModule } from '@angular/common/http';

And then in the imports section, add the HttpClientModule :

imports : [
    HttpClientModule,
    //...Other Modules Here...
]

And that’s it! You only need to do this in the root AppModule and don’t need to reimport it elsewhere in other modules within your app.

In some very rare cases, you may need to call a child component’s method directly from a parent component. Generally speaking, this should be seen as only a last resort. Component communication in most cases should be limited to data binding (Both input and output), and and in some cases using a service to emit values between two components.

However, there has been times where I’ve had race conditions between two components that can only be solved by a very precise order of methods being called. This means that I need them to happen synchronously. For that, this method is a life saver , and it’s simple too!

Consider I have the following component :

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss']
})
export class ParentComponent implements OnInit {
}

And I also have a child component like so :

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit {
    callMe(value : string) { 
        console.log('Called : ' + value);
    }
}

Inside the view of parent.component.html, I place the child component.

<app-child></app-child>

Now inside my parent component, I can actually use ViewChild like so to get a direct reference to the child.

export class ParentComponent implements OnInit {
    @ViewChild(ChildComponent, {static : true}) child : ChildComponent;
}

Notice that I don’t pass in a “string” to find like we sometimes do with a ViewChild, we pass in the actual type of component we are looking for.

Then, it’s as easy as calling something on our child.

export class ParentComponent implements OnInit {
    @ViewChild(ChildComponent, {static : true}) child : ChildComponent;
	
    callMyChild(){
        child.callMe('Calling from the parent!');
    }
}

The usual ViewChild rules apply however that generally speaking, you only have access to ViewChild references after the view is initialized (So you cannot access them in an ngOnInit method, you have to use ngAfterViewInit).

Again, it’s typically much better to use data binding or a “joining service” for the two components to communicate. But often it can be hard to sync up the precise order of actions that need to happen. So for that, ViewChild is the winner.