Search code examples
angularangular6angular-reactive-formsangular4-formsviewchild

Child To Parent Value access using ViewChild


I have read about articles in angular6, 3 ways to communicate in child to parent.if its wrong,please demonstrate if possible 1)output emitter 2)using viewchild 3)shared Service.

So here i need to understand how to communicate the viewchild from child to parent.

In below demo, have created a form in child component,when child component form is valid, that should be reflected in parent component.In this demo when components gets loaded in ngafterViewInit hook the view child value , its working as expected , but when type some thing , child component form is valid,button enabled in child form ,those changes not reflected in the parent component which needs to valid , but its not working as expected. can anyone give the best approach?

parent component.html

<h1> Parent Component</h1>

<button class="btn btn-danger " disabled="{{check}}">CheckParentEnable</button>
<div class="childComponent">
<app-child-component></app-child-component>
 k2
  </div>

parent component.html

import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from './child/child.component';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit {

  public check: boolean;
  @ViewChild(ChildComponent) myname: ChildComponent;


  constructor() {

  }
  ngAfterViewInit() {
    this.check = this.myname.loginForm.valid;
  }

}

Child.component.html

<h4>childComponentArea<h4>

  <h1>Welcome to child component</h1>


<form [formGroup]="loginForm">

<input type="email" formControlName="email" placeholder="Email" >

<button class="btn btn-danger" [disabled]="loginForm.invalid">Submit</button>
</form>

child.component.ts

import { Component, EventEmitter, Input,Output, OnInit } from '@angular/core';
import { FormControl, FormGroup,Validators } from '@angular/forms';
@Component({
  selector: 'app-child-component',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
  loginForm:FormGroup;
  name:string ='sahir';
  constructor() { }

  ngOnInit() {
    this.createForm();
  }


 private createForm() {
    this.loginForm = new FormGroup({
      // tslint:disable-next-line
      email: new FormControl('', [Validators.required])

    });
  }

  k8

}

demo


Solution

  • You probably need ngAfterViewChecked life cycle hook for your requirement. ngAfterViewInit of parent wont be called for every child component value changed, instead ngAfterViewChecked would be called. And also you need to push the change detection within parent into ViewChecked life cycle hook, or else you will get ExpressionChanged error in this line.

    this.check = this.myname.loginForm.valid;
    

    So this is the code that should work

    import { Component, ViewChild, AfterViewChecked, ChangeDetectorRef } from '@angular/core';
    constructor(private cdr : ChangeDetectorRef) {
    
    }
    
    ngAfterViewChecked() {
         console.log('view checked')
         this._check = this.myname.loginForm.valid;
         console.log(this.myname.loginForm.valid);
         this.cdr.detectChanges();
    }
    

    An also instead of disabled="{{check}}", use [disabled]="!check"

    DEMO