DEV Community

Cover image for Component Interactivity in angular 14
Wisdom John ikoi
Wisdom John ikoi

Posted on • Updated on

Component Interactivity in angular 14

Simple two-way communication between two or more related components is known as component interaction; this includes the exchanging of information, properties, events, and functions.

Once an Angular component is formed, component associations are established. The family tree expands as you begin layering components inside one another. Parents, kids, siblings, and other family members are just a few examples of how components are connected.

Nesting is a characteristic that naturally comes from HTML. An element in HTML that is nested inside of another element inherits the parent element's attributes and properties. That isn't necessarily the case with Angular.

You will need to carry out some additional configuration to allow parents to exchange data with children or children to share data with parents or related components.

In Angular, this is made possible using decorators, view children, and Angular services.

Key takeaway

  • Understand Components interactivity in angular.

Pre-requisite.

  • Fundamentals of angular/angular components.
  • Decorators in angular/TypeScript
  • Nesting.

To enable Component interactivity and let data be shared between components in angular you will have to consider the kind of relationship that exists between the components. 

Parent => child

A Child Component can receive data from its parent component through the @input decorator. After creating a relationship the child component imports the @input decorator and declares the decorator in the component class and the data it is trying to receive from the parent.

Generate three angular components to get started, name them child, parent, and relative.

Here is the CSS file for the three components give them any three different background colors to see the difference.

div {
    background-color: rgb(255, 47, 47);
    height: 200px;
    width: 200px;
}
Enter fullscreen mode Exit fullscreen mode

Code along!!

import { Component } from '@angular/core';

  @Component({
  selector: 'app-parent',
  templateUrl: '



Parent Element

Message: {{message}}


',
  styleUrls: ['./parent.component.css']
})
export class ParentComponent {

  message:string = "Received from parent";
  
}
Enter fullscreen mode Exit fullscreen mode

On the parent component above, input the message string property into the child, now the parent and child component is supposed to display the same data based on shared connectivity, which is the message string.

In the parent component, a message data is declared and inside the nested tag of the child component, the property is referenced using the variable name [message]=" message" this attribute binds the message property between the parent and child.

Now below is the child component. here you have to import the input decorator to the child component class and also declare the string variable "message" with the input decorator in front of it.

import { Component, Input} from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: '
 

Child Component

    Message: {{message}}

',
  styleUrls: ['./child.component.css']
})
export class ChildComponent {
 
@Input() message:string | undefined;

}
Enter fullscreen mode Exit fullscreen mode

Result
Both Components should display "Received from parent" now they share the same data.

Child => parent
A child can Share data with its parent Via the @output decorator and also share a function Via event emitter. here you are going to pass two data to the parent component, a function, and a property. the output decorator is a normal method for property sharing from child to parent, while the event emitter shares a function with the parent component. in cases where you bind data and share, it's okay to use just the output decorator.

In the example below you will be binding a message variable and also an event that changes both parent and child data on Click.

start by updating the child component with the required imports.

 { Component, OnInit, Output, EventEmitter} from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: ' 



Child Component 

        message {{childMessage}}
        Send message

',
  styleUrls: ['./child.component.css']
})
export class ChildComponent {

  childMessage: string = "xenxei 46"

  @Output() messageEvent = new EventEmitter();

  sendMessage() {
    this.messageEvent.emit(this.childMessage)
  }
}
Enter fullscreen mode Exit fullscreen mode

"Send Message" is the event you want to share and the property you are sharing with the parent is named "childMessage".

Now on the parent, you will receive the emitted event with the nested tag of the child element renaming the variable to receive the property to "receiveMessage".

import { Component, } from '@angular/core';

@Component({
  selector: 'app-parent',
  templateUrl: '



Parent Element

Message: {{childMessage}}



',
  styleUrls: ['./parent.component.css']
})
export class ParentComponent  {
  childMessage = '';

  receieveMessage($event: string) {
    this.childMessage = $event
  }

}

Enter fullscreen mode Exit fullscreen mode

The child message is passed as an empty string and when the button is clicked the message is shown on the parent component.

Child => Parent using @viewChild
Another method to simply pass property from a child to a parent is via the @viewchild decorator. 

In the child component below, the property is viewed on the parent component as soon as the component is initialized. The child property is stored using ViewChildmsg.

import { Component} from '@angular/core';
@Component({
  selector: 'app-child',
  templateUrl: '




Child Component

say: {{viewChildmsg}}

',
  styleUrls: ['./child.component.css']
})
export class ChildComponent  {

  viewchildmsg: string = "Hola xenxei!"

}

Enter fullscreen mode Exit fullscreen mode

The parent component views the child's property by using the following:

import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from '../child/child.component';

@Component({
  selector: 'app-parent',
  templateUrl: '



Parent component

{{viewchildmsg}}


',
  styleUrls: ['./parent.component.css']
})

export class ParentComponent implements AfterViewInit  {

  @ViewChild(ChildComponent) child: any;

  viewchildmsg!:string;

 ngAfterViewInit(){
  this.viewchildmsg = this.child.viewchildmsg;
 }

}

Enter fullscreen mode Exit fullscreen mode

In the rendered screen both the parent and child components should carry the same message. The @viewChild decorator carries the property from the child, stores the value on the new variable or the same variable as the case may be, and tells it to render After the view is initialized by taking the property of the view child. 

Sharing Data Between Relative Components 
In angular, data can be shared between unrelated components or relative components.
 
A function or properties (Data) can be shared with a related component, this is made possible through angular service.

Generate a service component named data. to generate angular service use "ng generate service [service name]".

Update the generated angular service.

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class DataServiceService {

  private messageSource = new BehaviorSubject("shared message");
  currentMessage = this.messageSource.asObservable();

  constructor() { }

  changeMessage(message: string) {
    this.messageSource.next(message)
  } 
}

Enter fullscreen mode Exit fullscreen mode

Message source is a variable assigned as a behavior subject and a string type "shared message" later passed to current message as an observable. Why was all this process passed through? well there is no need to worry This is just a convention there are other logic going on under the hood.

To pass the string "shared message" to the child component, import the service to the child component and other dependencies as shown in the code below.

Pass a variable to the message in the child component and interpolate the message variable on the template to see "shared message" on your view.

Update the child component as directed:

import { Component, OnInit} from '@angular/core';
import { DataServiceService } from '../data.service';


@Component({
  selector: 'app-child',
  templateUrl: ' 



Child Component

    

Message from service says: {{message}}



',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {

  message!: string;

  constructor(private data: DataServiceService) { }

  ngOnInit(): void {
    this.data.currentMessage.subscribe(message => this.message = message)
  }

  newMessage() {
    this.data.changeMessage("Hello from relative component")
  }

}

Enter fullscreen mode Exit fullscreen mode

Now that the property and the function have been passed to the child component pass it to the parent component as well.

import { Component, OnInit} from '@angular/core';
import { DataServiceService } from '../data.service';

@Component({
  selector: 'app-parent',
  templateUrl: '


Parent Component



Message:  {{message}}




',
  styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit  {

  constructor(private data: DataServiceService) { }

  message!: string;

  ngOnInit(): void {
    this.data.currentMessage.subscribe(message => this.message = message)
  }

}

Enter fullscreen mode Exit fullscreen mode

On the Relative component do the same, This is where the function is initialized. on the relative component.ts, the function is written to change the shared message currently displaying on all three components.
Both parent and child components should respond to the change on click.

 

import { Component, OnInit} from '@angular/core';
import { DataServiceService } from '../data.service';

@Component({
  selector: 'app-relative',
  templateUrl: '

    
Relative component

    New Message


',
  styleUrls: ['./relative.component.css']
})
export class RelativeComponent implements OnInit {

  message!:string;

constructor (private data: DataServiceService)

ngOnInit(): void
Subscribe(message = this.message) to this.data.currentMessage
  }

  newMessage() {
this.data.changeMessage ("Hello from a sibling")
  }

}

Enter fullscreen mode Exit fullscreen mode

Conclusion

A component interaction scenario occurs when a function can be written in a component and used or called up in another component.

or when data or logic needs to be handled by a parent but the view is gotten from a child component. The same data, once manipulated, will take effect on every component that shares the data.

Component interactivity comes in handy when building a large application that is split into several components.

In summary, this is made possible using the following tools:

  • @input decorators: Passes information from parent to child.
  • @output decorators: Transfers data from parent to child. @viewchild: Passes information from a parent to a child. Services: shares data between related or unrelated components.

Source code is at my GitHub repo: https://github.com/xenxei46/Angular/tree/main/Component%20Interaction

Top comments (0)