3 ways to communicate between Angular components

3 ways to communicate between Angular components
This article is written for Angular 2+**.** At the time of writing the latest version was Angular 4.

Update (August 2018): Still valid for Angular 6

It’s written for beginners — if you are an advanced or intermediate Angular developer you probably already know all these techniques.

Edit: Although, the title of this article is a bit misleading because we do not really want to communicate between components directly. Our components should be isolated and encapsulated. I chose this title because I think developers struggling with this will be googling it this way.

How to communicate between components? This is the topic I’ve seen many new Angular developers to struggle with. I will show you the three most common approaches, with examples that fits different use cases.

There is also the “redux way” which I could cover in another article in the future.

Imagine the use case that you have the sidebar in your application. Sidebar is either open or closed. You have the side-bar component and then you have component (or multiple components) that can open/close it or ask for its state.

I will describe three ways of implementing this behaviour

  1. Passing the reference of one component to another
  2. Communication through parent component
  3. Communication through Service

Each one of these examples has the demo application with code inspections on StackBlitz and github repository.

1. Passing the reference of one component to another

This solution should be used when components have dependency between them. For example dropdown, and dropdown toggle. They usually can’t exist without each other.

Demo
Github repository

We will create the side-bar-toggle component which will have the side-bar component as input and by clicking on the toggle button we will open/close the side-bar component.

Here is the relevant code:
app.component.html

app component

<app-side-bar-toggle [sideBar]="sideBar"></app-side-bar-toggle>
<app-side-bar #sideBar></app-side-bar>

side-bar-toggle.component.ts

@Component({
  selector: 'app-side-bar-toggle',
  templateUrl: './side-bar-toggle.component.html',
  styleUrls: ['./side-bar-toggle.component.css']
})
export class SideBarToggleComponent {

  @Input() sideBar: SideBarComponent;

  @HostListener('click')
  click() {
    this.sideBar.toggle();
  }

}

side-bar.component.ts

@Component({
  selector: 'app-side-bar',
  templateUrl: './side-bar.component.html',
  styleUrls: ['./side-bar.component.css']
})
export class SideBarComponent {

  @HostBinding('class.is-open')
  isOpen = false;

  toggle() {
    this.isOpen = !this.isOpen;
  }

}

2. Communication through parent component

Can be used when it’s easy to control shared state between components through their parent component and you don’t feel like you want to create new service or create some boilerplate code, because of one variable.

Demo
Github repository

Implementation of this approach is almost the same as the previous one, however side-bar-toggle doesn’t receive side-bar component. Instead parent component holds sideBarIsOpened property which is passed to the side-bar component.

app.component.html

<app-side-bar-toggle (toggle)="toggleSideBar()"></app-side-bar-toggle>
<app-side-bar [isOpen]="sideBarIsOpened"></app-side-bar>

app.component.ts

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent {
  sideBarIsOpened = false;

  toggleSideBar(shouldOpen: boolean) {
    this.sideBarIsOpened = !this.sideBarIsOpened;
  }
}

side-bar-toggle.component.ts

@Component({
  selector: 'app-side-bar-toggle',
  templateUrl: './side-bar-toggle.component.html',
  styleUrls: ['./side-bar-toggle.component.css']
})
export class SideBarToggleComponent {

  @Output() toggle: EventEmitter<null> = new EventEmitter();

  @HostListener('click')
  click() {
    this.toggle.emit();
  }

}

side-bar.component.ts

@Component({
  selector: 'app-side-bar',
  templateUrl: './side-bar.component.html',
  styleUrls: ['./side-bar.component.css']
})
export class SideBarComponent {

  @HostBinding('class.is-open') @Input()
  isOpen = false;

}

3. Communication through service

Finally this option is useful and should be used when you have component that is controlled or its state is asked from multiple instances.

Demo
Github Repository

Now we have multiple places across the application that will need to access our side-bar component. Let’s see how we do it.

We will now create side-bar.service.ts so we will have:

  • side-bar.service.ts
  • side-bar.component.ts
  • side-bar.component.html

Side bar services will have toggle method and change event so every component that will inject this service can be notified that panel was opened or can toggle it.

In this example neither side-bar component or side-bar-toggle component has input parameters, because they communicate through service.

Now the code:
app.component.html

<app-side-bar-toggle></app-side-bar-toggle>
<app-side-bar></app-side-bar>

side-bar-toggle.component.ts

@Component({
  selector: 'app-side-bar-toggle',
  templateUrl: './side-bar-toggle.component.html',
  styleUrls: ['./side-bar-toggle.component.css']
})
export class SideBarToggleComponent {

  constructor(
    private sideBarService: SideBarService
  ) { }

  @HostListener('click')
  click() {
    this.sideBarService.toggle();
  }
}

side-bar.component.ts

@Component({
  selector: 'app-side-bar',
  templateUrl: './side-bar.component.html',
  styleUrls: ['./side-bar.component.css']
})
export class SideBarComponent {

  @HostBinding('class.is-open')
  isOpen = false;

  constructor(
    private sideBarService: SideBarService
  ) { }

  ngOnInit() {
    this.sideBarService.change.subscribe(isOpen => {
      this.isOpen = isOpen;
    });
  }
}

side-bar.service.ts

@Injectable()
export class SideBarService {

  isOpen = false;

  @Output() change: EventEmitter<boolean> = new EventEmitter();

  toggle() {
    this.isOpen = !this.isOpen;
    this.change.emit(this.isOpen);
  }

}

If you have another way of doing this or you have any problems with examples above let me know in the comments.

30s ad

Angular 5 Advanced MasterClass & FREE E-Book

Angular 5 NgRx Store Masterclass & FREE E-Book

Ultimate Angular 5 with TypeScript and Bootstrap 4

Angular 2 Step by Step: From Beginner to Advanced

Suggest:

Angular Tutorial - Learn Angular from Scratch

Web Development Tutorial - JavaScript, HTML, CSS

Javascript Project Tutorial: Budget App

Test Driven Development with Angular

JavaScript Programming Tutorial Full Course for Beginners

E-Commerce JavaScript Tutorial - Shopping Cart from Scratch