5
votes

I simply want to update a boolean value in my parent component on click of a button in my child component. I have a slide-out child component that I hide and show based on a dynamic ngClass. The class is set based on the boolean value from the parent. However when I close that component from a button in the child, I want to update the boolean value in the parent:

The parent component typescript:

export class AppComponent implements OnInit   {

  showFlyout: boolean

  constructor() {}

  ngOnInit() {
    this.showFlyout = false;
  }
}

And parent html:

<main>

  <button (click)="showFlyout = !showFlyout"><i class="fa fa-check"></i>Show Flyout</button>

  {{showFlyout}}

  <app-child id="flyout" [ngClass]="showFlyout ? 'active' : ''"></app-child>

</main>

The child component typescript:

export class ActivateFlyoutComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

  closeActivationFlyout() {
    const flyout = document.getElementById('flyout');
    flyout.classList.remove('active');
  }

}

And child component html:

<button (click)="closeFlyout()">Close</button>

Here's a Stackblitz. You can see clicking the parent button properly toggles the class but how can I update that boolean from click in the child and therefore make the closeActivationFlyout() method unnecessary in the child component?

2
use @Output decorator with EventEmitter of type boolean - Niladri
My answer forgot to change the state on the child element. Please accept Jun's answer. - Randy Casburn
@JordanBarber manipulating the dom directly is not the proper way to do such thing, - SEY_91
@RandyCasburn, that is precisely why I asked this question. I knew DOM manipulation was the wrong way and the answer I received has helped me to eliminate that. Thanks for your help! - JordanBarber

2 Answers

5
votes

Use @Output() like the others have mentioned, but it needs to emit an event and you also need to check for the event being triggered in the parent html.

Here's a working StackBlitz

In the child component.

@Output() onCloseClick = new EventEmitter();

closeFlyout() {
  this.onCloseClick.emit();
}

And in the parent components html.

<app-child id="flyout" [ngClass]="showFlyout ? 'active' : ''" (onCloseClick)="showFlyout = false"></app-child>

You can also create a function in the parent component, and trigger that like (onCloseClick)="doFunction()"

1
votes

You can use two-way databinding to make it works:

AppComponent:

<app-child id="flyout" [(showFlyoutModel)]="showFlyout" [ngClass]="showFlyout ? 'active' : ''"></app-child>

ChildComponent :

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

    @Component({
      selector: 'app-child',
      templateUrl: './child.component.html'
    })
    export class ChildComponent implements OnInit {
      @Input()
      showFlyoutModel;

      @Output()
      showFlyoutModelChange = new EventEmitter<boolean>();
      constructor() { }

      ngOnInit() {
      }

      closeFlyout() {
        this.showFlyoutModelChange.emit(!this.showFlyoutModel);
      }

    }

https://stackblitz.com/edit/angular-v95emc?file=app%2Fchild-component%2Fchild.component.ts