Search code examples
angularviewchild

Angular 8: using ViewChild get a method result from a child to parent after that method is invoked in child component


In my child component i have two buttons like following:

child-component.html

<div>
   <button (click)="getFirstData()">First</button>
   <button (click)="getLastData()" >Last</button>
</div>

In child-component.ts:

export class ChildComponent implements OnInit, AfterViewInit {
  firstItem: number;
  lastItem: number;

  constructor() {
  }

  ngOnInit() {
  }

  ngAfterViewInit(): void {
  }

  getFirstData() {
    this.firstItem = 1;
    return this.firstItem;
  }

  getLastData() {
    this.lastItem= 10;
    return this.lastItem;
  }

}

In parent component i need to receive the firstItem and lastItem data after the respective method is invoked from child component. When i try to get that in parent component using ViewChild in AfterViewInit lifecycle hook like following:

parent-component.ts

export class ParentComponent implements OnInit, AfterViewInit {
  @ViewChild(ChildComponent, {static: true}) child: ChildComponent;

  first: number;
  last: number;

  ngOnInit() {
  }

  ngAfterViewInit() {

    console.log('first value ', this.child.getFirstData());
    console.log('last value ', this.child.getLastData());

  }

  getValues(): void {
    // some operations heer
  }
}

I can't get that data from child.

My goal is to receive those data after method invoked in child after button click event there. And after receiving, i need to call the getValues() method in parent component.

How can i achieve this ?


Solution

  • Example - Output decorator

    child component:

    export class ChildComponent implements OnInit, AfterViewInit {
      firstItem: number;
      lastItem: number;
    
      @Output() firstItemChanged = new EventEmitter<number>();
      @Output() lastItemChanged = new EventEmitter<number>();
    
      constructor() {
      }
    
      ngOnInit() {
      }
    
      ngAfterViewInit(): void {
      }
    
      getFirstData() {
        this.firstItem = 1;
        this.firstItemChanged.emit(this.firstItem);
      }
    
      getLastData() {
        this.lastItem= 10;
        this.firstItemChanged.emit(this.lastItem);
      }
    
    }
    

    Parent component html:

        <child-component (firstItemChanged)="handleFirstItemChanged($event)" (lastItemChanged)="handleLastItemChanged($event)"></child-component>
    

    Parent component:

    export class ParentComponent {
    
      handleFirstItemChanged(value: number): void {
        // handle event
      }
    
      handleLastItemChanged(value: number): void {
        // handle event
      }
    }
    

    Example - BehaviorSubject

    child component:

    interface State {
      firstItem: number;
      lastItem: number;
    }
    
    export class ChildComponent {
    
      state = new BehaviorSubject<State>({
        firstItem: 0,
        lastItem: 0
      });
    
      constructor() { }
    
      firstButtonClicked() {
        const newState = this.state.value;
        newState.firstItem = 1;
        this.state.next(newState);
      }
    
      lastButtonClicked() {
        const newState = this.state.value;
        newState.lastItem = 1;
        this.state.next(newState);
      }
    }
    

    Parent component:

    export class ParentComponent implements AfterViewInit {
    
      @ViewChild(ChildComponent, {static: true}) child: ChildComponent;
    
      ngAfterViewInit(): void {
        this.child.state.subscribe(state => {
          // handle
        });
      }
    }