DEV Community

Cover image for Component Interaction in Angular
Ankit Kumar Sharma
Ankit Kumar Sharma

Posted on • Updated on

Component Interaction in Angular

Hello guys, I am writing my first blog on Angular. As we know, Angular is a module-component based frontend-end framework.

By this tutorial, you can learn, how we can share data between component in Angular in different way. I am providing those way then you can understand easily.

  1. Communication through Parent Component to Child Component (Input Decorator)
  2. Communication through Child Component to Parent Component (ViewChild Decorator)
  3. Communication through Child Component to Parent Component (Output/EventEmitter Decorator)
  4. Communication through Sibling Components (As a service)

**

Communication through Parent Component to Child Component (Input Decorator)

**
Most common way to introduce data share via Input decorator that allow data to passed via template with data binding. Here, data list sharing via parent component to child component. I am showing a data list via this way.

parent.component.ts

@Component({
  selector: 'app-parent',
  template: `<app-child [data]="dataList"></app-child>`,
  styleUrls: ['./parent.component.scss']
})
export class ParentComponent implements OnInit {
  public dataList: ParentDataList[] = PARENT_DATA_LIST;
  constructor() { }
  ngOnInit(): void {
  }
}
Enter fullscreen mode Exit fullscreen mode

child.component.ts

@Component({
  selector: 'app-child',
  template: `<div class="table-responsive">
  <table class="table">
    <tr>
      <th>Id</th>
      <th>User ID</th>
      <th>Title</th>
      <th>Body</th>
    </tr>
    <tr *ngFor="let item of data">
      <td>{{item.id}}</td>
      <td>{{item.userId}}</td>
      <td>{{item.title}}</td>
      <td>{{item.body}}</td>
    </tr>
  </table>
</div>`,
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit {
  @Input() data!: ParentDataList[];
  constructor() { }
  ngOnInit(): void {
  }
}
Enter fullscreen mode Exit fullscreen mode

**

Communication through Child Component to Parent Component (ViewChild Decorator)

**
ViewChild decorator , we can passed data via child component to parent component. When we inject ViewChild into parent component, then it give access to parent with it’s variables and functions, then we can use as per our requirement. I am trying to add list via this way.

parent.component.ts

@Component({
  selector: 'app-parent',
  template: `<button class="primary-btn" (click)="addList()">Add List</button>
<app-child></app-child>`,
  styleUrls: ['./parent.component.scss']
})
export class ParentComponent implements OnInit, AfterViewInit {
  @ViewChild(ChildComponent) child!: ChildComponent;
  constructor() { }
  ngOnInit(): void {
  }
  addList(){
     let obj = {
        id: 1,
        userId: 123,
        title: 'ankit',
        body:'every thing mcm complrter'
      }
     this.child.arrList = [...this.child.arrList, obj];
  }
  ngAfterViewInit(){
    this.child.showList(true);
  }
}
Enter fullscreen mode Exit fullscreen mode

child.component.ts

@Component({
  selector: 'app-child',
  template: `<table *ngIf="collapseList" class="table">
  <tr *ngFor="let item of arrList;let i=index;">
    <td>{{item.id}}{{i}}</td>
    <td>{{item.userId}}{{i}}</td>
    <td>{{item.title}}{{i}}</td>
    <td>{{item.body}}{{i}}</td>
  </tr>
</table>`,
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit {
  public collapseList!: boolean
  public arrList:DataList[] = [];
  constructor() { }
  ngOnInit(): void {}
  showList(value:any){
    this.collapseList = value;
  }
}
Enter fullscreen mode Exit fullscreen mode

**

Communication through Child Component to Parent Component (Output/EventEmitter Decorator)

**

Output decorator, This is the another way to share data from child component to parent component via event emitter, as in emit data from the child component to parent component. It works like a event binding in angular. We can share data on any type of event occur via this way like on change, on click etc. I create a small addition/multiply/subtraction/divide functionality by this way.

parent.component.ts

@Component({
  selector: 'app-parent',
  template: `<div class="row">
  <div class="col-md-2">
    <input #text1 (change)="text1Data(text1.value)" type="number" value="0" class="form-control">
  </div>
  <div class="col-1">
    <h2 class="ak-title-lg">{{optSymbal}}</h2>
  </div>
  <div class="col-md-2">
    <input #text2 (change)="text2Data(text2.value)" type="number" value="0" class="form-control">
  </div>
  <div class="col-md-1">
    <p class="ak-title">=</p>
  </div>
  <div class="col-md-3">
    <input type="text" class="form-control" [value]="result" disabled>
  </div>
</div>
<app-child (btnClick)="operationClick($event)"></app-child>`,
  styleUrls: ['./parent.component.scss']
})
export class ParentComponent implements OnInit {
  public inputValue1: number = 0;
  public inputValue2: number = 0;
  public result: number = 0;
  public optSymbal:any;
  constructor() {}
  text2Data(value: number) {
    this.inputValue2 = value;
  }
  text1Data(value: number) {
    this.inputValue1 = value;
  }
  ngOnInit(): void {}
  operationClick($event: any) {
    this.optSymbal = $event;
    switch ($event) {
      case OPERATION.addition:
        this.result = this.inputValue1 + this.inputValue2;
        break;
      case OPERATION.subtract:
        this.result = this.inputValue1 - this.inputValue2;
        break;
      case OPERATION.multiply:
        this.result = this.inputValue1 * this.inputValue2;
        break;
      case OPERATION.division:
        this.result = this.inputValue1 / this.inputValue2;
        break;
      default:
        break;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

child.component.ts

@Component({
  selector: 'app-child',
  template: `<table class="table">
  <tr class="row">
    <td class="col-md-3 col-6" *ngFor="let item of btnArr;let i=index;">
      <button class="primary-btn" (click)="changeData(item.opt)">{{item.title}}</button>
    </td>
  </tr>
</table>`,
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit {
  @Output() btnClick:EventEmitter<any> = new EventEmitter();
  btnArr = BTN_OPERATION_ARR;
  constructor() { }
  ngOnInit(): void {
  }
  changeData(value:string){
    this.btnClick.emit(value);
  }
}
Enter fullscreen mode Exit fullscreen mode

**

Communication through Sibling Components (As a service)

**

In this way, we can use multiple scenario like via RxJS, get/set methods and more ways. I am explaining here via getter/setter methods, with RxJS BehaviorSubject will discuss in next blog. So I am trying to show and hide a data via service method.

sibling1.component.ts

@Component({
  selector: 'app-sibling1',
  template: `<p>sibling1 works!</p>
<h2 class="ak-title">This is a <span [ngClass]="{'true': show_flag, 'false': !show_flag}">{{show_flag ? 'True':'False'}}</span> condition</h2>
<a class="primary-btn" routerLink="child">Go to child >>></a>`,
  styleUrls: ['./sibling1.component.scss']
})
export class Sibling1Component implements OnInit {
  show_flag:any;
  constructor(private dataService: DataService) { }
  ngOnInit() {
    this.getData()
  }
  getData(){
    this.show_flag = this.dataService.getData();
  }
}
Enter fullscreen mode Exit fullscreen mode

sibling2.component.ts

@Component({
  selector: 'app-sibling2',
  template: `<button class="primary-btn" routerLink="/">Back</button>
<app-contact [data]="contactData"></app-contact>
<p>child works!</p>
<button class="secondary-btn" (click)="changeCondition()">Change Condition</button><br><br>
<a class="primary-btn" routerLink="/service-based"> <<< Go to Parent</a>`,
  styleUrls: ['./sibling2.component.scss']
})
export class Sibling2Component implements OnInit {
  contactData = CONTACT_HEADER;
  constructor(private dataService: DataService) { }
  changeValue:any;
  ngOnInit() {
    this.changeValue = this.dataService.getData();
  }
  changeCondition(){
    this.changeValue = !this.changeValue;
    this.dataService.setData(this.changeValue);
    alert('Done, Now click on Go to Parent');
  }
}
Enter fullscreen mode Exit fullscreen mode

data.service.ts

@Injectable({
  providedIn: 'root'
})
export class DataService {
  public isEnable: boolean = false;
  constructor() { }
  // we are communication data between two component via service -- getter/setter method
  //-----------------------------------------------------------
  // setter method
  setData(data:any){
    this.isEnable = data;
  }
  // getter method
  getData(){
    return this.isEnable;
  }
}
Enter fullscreen mode Exit fullscreen mode

If you have any query or doubts, please quick add comment, will try to resolve your query.

GitHub Source Code
Demo

https://www.ankitkumarsharma.com/

Also please follow me on GitHub , Twitter , Medium, and Dev for more updates on articles with hands on code queries.

Top comments (2)

Collapse
 
stradivario profile image
Kristiqn Tachev

What you are describing here is totally a bad practice and no one should use it.

To interact with parent component via child component is making too much coupling and actually it creates unreadable code.

I didn't saw not even one observable here why?

In the service you should have observables and the component should subscribe with async pipe instead relying on Zone change detection mechanism.

If you now change the strategy of the component to OnPush you will end up with broken and not working code.

I recommend you also for advanced architectures ngrx to be used with Facade pattern.

Regards!

Collapse
 
ankit_k_sharma profile image
Ankit Kumar Sharma

Thanks for your valueable feedback.
I create it more simplely, also try it for freshers, who can easily understand , what is component interaction in angular, then they can use observaables, services as per their requirements. We can use observables as well and services. Also ngRx (State Management) is a different thing, it is for how we can manage state in angular, here I am explaining angular component interaction. for NgRx (State Management) will write another article.
Thank you again for your feedback.
Keep smiling