Send data from child to parent

Here basic logic behind the functionality has been discussed. So, Child can communicate with the parent component in the following manner:

  1. ViewChild
    Import ViewChild in the parent component and access the child function of Child component or any element reference in the child component template.
    Parent’s component file:
import { Component, OnInit ,ViewChild,AfterViewChecked} from '@angular/core';
import { FormBuilder, FormGroup, FormArray, FormControl} from "@angular/forms";
import { CategoriesService } from 'src/app/services/common/categories.service';
// Import the other required classes here
//.....
export class AddEditProductComponent implements OnInit,AfterViewChecked {
  @ViewChild(ChildrenDropdownComponent) child: ChildrenDropdownComponent;
chkdVal = null;
data = {
"categories":[{"id": 35, "parent_id": 0, "name": "Chairs"},
{"id": 39, "parent_id": 0, "name": "Beds"},
{"id": 40, "parent_id": 0, "name": "Dressings"},
{"id": 41, "parent_id": 0, "name": "Tables"}]
}
 // Your constructor here 
constructor(public fb: FormBuilder, 
private catService:CategoriesService){}
//Inject other services if required
 ngOnInit(): void {
    var attributes= new Array();

    this.productForm = this.fb.group({
      
catList:new FormArray([])
    });

// Here object array returned by category service has been used to //populate catFormArray 
     data['categories'].forEach(() => this.catFormArray.push(new FormControl(false)));
 });
  }

  ngAfterViewChecked() {
    if(this.child) {
      var result = this.child.checkValue();
        this.chkdVal = result;;
      // Initialize the instance variable and use it in your required
     // function
   }

   onSubmit() {
    console.log(this.chkdVal);
     // So we can further process those values in our code
   }
 }

Now we place the change event on checkbox input in the child component template. Here parentForm is the form group name of parent form that have passed to child.

Make sure that you declare the child component :

<app-children-dropdown (subCategories) = "checkValue($event)" [childList]="categories[i].children" [parentForm]="productForm"></app-children-dropdown>

in the parent’ s template file as declared below

Parent’s template file

<form class="form-product" [formGroup]="productForm">
        <div class="card-body">
			<div class="row">
				<div class="col-md-4">       
                  <div class="form-group">
                    <label>Name</label>
                    <input type="text" class="form-control" formControlName="name">

                  </div>
                  <div class="form-group">

					  <div formArrayName="catList" class="parent" *ngFor="let cat of catFormArray.controls ;let i = index">
						<input type="checkbox" [value]="categories[i].id" [formControlName]="i">
						 <label>{{ categories[i].name }}</label> 
						   <app-children-dropdown [childList]="categories[i].children" [parentForm]="productForm"></app-children-dropdown>
					  </div>
				  </div>
				</div>
			</div>
		</div>
</form>


Child’s template file

<div [formGroup]="parentForm">
<div formArrayName="catList" class="child" *ngFor="let subcat of catFormArray.controls;let i = index"> 
    <input type="checkbox" [formControlName]="i" [value]="categories[i].id"(change)="checkValue()">
    <label>{{categories[i].name}}</label>
</div>
</div>

Whatever your event type (click on submit or change) bind it in the child component with function and return response.

Child’s component file

import { FormBuilder, FormGroup, FormArray, FormControl} from "@angular/forms";
//Import the other required classes
//.........

export class ChildrenDropdownComponent implements OnInit {
  @Input() childList;
  @Input() parentForm: FormGroup; 
 // Your constructor here 
constructor(public fb: FormBuilder){}

//Inject services if required
 ngOnInit(): void {
    this.parentForm = this.fb.group({
      catList:new FormArray([])
    });
    this.childList.forEach(() => this.catFormArray.push(new FormControl(false)));
    
  }
   checkValue(){
 var res =  this.childList 
    .filter((cat, catIdx) => this.catFormArray.controls.some((control, controlIdx) => catIdx === controlIdx && control.value))
    .map(cat => cat.id);
      return res;
   }
}

2. @Output : With help of Output decorator. This way is more productive as compare to ViewChild if I have to access the array of values of any input field of child component in the parent function. Also, it’s more convenient.

Import the Output and EventEmitter in the child component

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

export class ChildrenDropdownComponent implements OnInit {

  @Input() parentForm: FormGroup;
  @Output() subCategories = new EventEmitter();
   
checkValue($event){ 
    var res = this.categories
    .filter((cat, catIdx) => this.catFormArray.controls.some((control, controlIdx) => catIdx === controlIdx && control.value))
    .map(cat => cat.id);

    this.subCategories.emit(res);
   
  }


}  
}

Child’s component template file

<div [formGroup]="parentForm">
<div formArrayName="catList" class="child"  *ngFor="let subcat of catFormArray.controls;let i = index"> 
    <input type="checkbox" [formControlName]="i" (change)="checkValue(categories[i].id)">
    <label>{{categories[i].name}}</label>

</div>
</div>

Parent’s component

  <app-children-dropdown (subCategories) = "checkValue" [childList]="categories[i].children" [parentForm]="productForm"></app-children-dropdown>
//We will create checkValue function in the parent 
export class AddEditProductComponent implements OnInit {
  productForm: FormGroup;

  chkdVal = [];

  checkValue(data){
    this.chkdVal.push(data);
     //Now again you can initialize the instance variables and use                              //it in the required function.
  }
 onSubmit() {
    console.log(this.chkdVal +'chkdata');
}

Parent’s template file

<form class="form-product" [formGroup]="productForm">
        <div class="card-body">
			<div class="row">
				<div class="col-md-4">       
                  <div class="form-group">
                    <label>Name</label>
                    <input type="text" class="form-control" formControlName="name">

                  </div>
                  <div class="form-group">

					  <div formArrayName="catList" class="parent" *ngFor="let cat of catFormArray.controls ;let i = index">
						<input type="checkbox" [value]="categories[i].id" [formControlName]="i">
						 <label>{{ categories[i].name }}</label> 
						   <app-children-dropdown (subCategories) = "checkValue($event)" [childList]="categories[i].children" [parentForm]="productForm"></app-children-dropdown>
					  </div>
				  </div>
				</div>
			</div>
		</div>
</form>

Leave a Reply

Your email address will not be published. Required fields are marked *