Component Interactions

In any web application different components need to talk to each other. Data consumption and data exposure is a very common way to do it.

Input

A component can receive data from its parent as long as the receiving component has specifically said it is willing to receive data.

In the context of the counter application I wish to set the initial value from the AppComponent . This is where Input fits in.

Here is how it can be done in code.

<!-- Parent component -->

<counter [counterValue]="myValue"></counter>

// myValue is property of ParentComponent <!-- Child component -->

export class CounterComponent {

@Input() counterValue = 0;

// this is input from the parent component

}

In the above example counterValue is enclosed between square brackets. This is a syntax for property binding. myValue is bound and passed to CounterComponent now its upto CounterComponent to accept the input which it does in the above example. Now the value which is set in the AppComponent is bound to counterValue in the CounterComponent .

TIP: Please note that this is a unidirectional flow. Properties from the parent component can only flow down the hierarchy not up. This is also represented in the flow chart above.

Now we have a one way communication setup in between our components but we also need to be able to communicate upwards. That is where Output comes into picture.

Output

A component can send data to its parent by triggering an event the parent listens to.

In the context of counter application when the value of counter is changed it also needs to get reflected in the AppComponent(parent component). This is where Output comes into picture.

Here is how it can be done in code.

<!-- Parent component -->

// Template

<counter #counter [counterValue]="myValue" (counterChange)="myValueChange($event);"></counter> // Component

myValueChange($event) {

this.myValue = $event.value;

} <!-- Child component -->

// Template

<button (click)="decrement();"> // Component

@Output() counterChange = new EventEmitter(); decrement() {

this.counterValue--;

this.counterChange.emit({

value: this.counterValue

})

}

In the example above we have wrapped counterChange in round brackets. This is the syntax for event binding in angular. Whenever it receives an emission from an EventEmitter it will run myValueChange function and the event would be caught in $event variable. This $event is not something you can choose at your will. This has to be $event only.

In CounterComponent we have created an Output which is an EventEmitter . We emit an event on decrement with the new value. This event gets caught in the parent component.

“Input” specifies which properties you can set on a component whereas “Outputs” identifies the events a component can fire to send information up the hierarchy to its parent.

Other ways of communication between parent and child component is by directly accessing child component from the parent component. There are 2 ways of doing this.

LocalRef

In this approach we access the child component directly inside the parent component template using a local reference and accessing its properties and methods.

Here is how it can be done in code.

<!-- Parent component --> // Template

<div class="counter__container">

<button (click)="counter.decrement()">-</button>

<input type="text" class="counter_input" [value]="myValue">

<button (click)="counter.increment()">+</button>

</div> <counter #counter [counterValue]="myValue" (counterChange)="myValueChange($event);"></counter> <!-- Notice how #counter is a local reference -->

In the example above #counter holds the reference to (CounterComponent)child component and using that we are accessing counter.decrement() method.

ViewChild

Previous approach where we got a reference to the child component inside the template looks fine but its doesn’t give much control for example what if we wanted to access the child component inside of the parent component. This can be useful for access the child components methods and properties.

Here is how it can be done in code.

<!-- Parent component -->

import {ViewChild} from ‘@angular/core’; // Template

<div class="counter__container">

<button (click)="decrement()">-</button>

<input type="text" class="counter_input" [value]="myValue">

<button (click)="increment()">+</button>

</div> // Component

@ViewChild(CounterComponent)

private counterComponent: CounterComponent; // Via ViewChild accessor

increment() {

this.counterComponent.increment();

} decrement() {

this.counterComponent.decrement();

}

In the above example we are accessing the CounterComponent using a ViewChild .

Child components in our view can be accessed from our parent component easily with @ViewChild. To get access to a component and its methods, we can use the @ViewChild decorator.

We are just calling child component methods using our parent component methods which we have bound to click events on the buttons in the parent component.

Other than these two methods, components which are not directly linked can also use services to communicate. Services can then be injected into the components. This way component not directly linked but not limited to that can communicate. I am leaving service for another post in future.