How to call a method from another component after

2019-08-22 02:50发布

I'm using MatMenu from Angular Material inside HeaderComponent. I just need to open the Menu under certain conditions (method), calling this method on ProductDetailComponent. However this method only works inside ngAfterViewInit(), after the view is loaded.

I found a way to comunicate from ProductDetailComponent to HeaderComponent, however there is a Children-Parent relationship to reach the components. HeaderComponent is called from AppComponent.

Here is AppComponent

<my-header [openMenu]="clickBehavior"></my-header>
<router-outlet></router-outlet> <!-- ProductComponent -->

ProductComponent

<router-outlet></router-outlet> <!-- ProductDetailComponent -->

ProductDetail component

export class ProductComponent {
  clickBehavior = new BehaviorSubject(null);

  click() {
    this.clickBehavior.next(1);
  }
}

ProductDetail markup

<!-- i need to move it to app component 
<my-header [openMenu]="clickBehavior"></my-header>
-->
<div>
  <button (click)="click()">Click</button>
</div>

Header component

export class HeaderComponent implements AfterViewInit {
  @ViewChild('trigger') trigger: MatMenuTrigger;
  @Input() openMenu: Observable<any>;

  ngAfterViewInit() {
    this.openMenu.subscribe(value => {
      if (value) {
        this.trigger.openMenu();
      }
    });
  }
}

Header markup

<button mat-button
        [matMenuTriggerFor]="menu"
        #trigger="matMenuTrigger">Menu
</button>
<mat-menu #menu="matMenu">
  <button mat-menu-item>Item 1</button>
  <button mat-menu-item>Item 2</button>
</mat-menu>

1条回答
Evening l夕情丶
2楼-- · 2019-08-22 03:23

You can achieve this by using a shared service and injecting the service where it is required.

Setup a shared service, i put methods to get, set and toggle the menu state.

SharedService.ts

import { Injectable } from '@angular/core';

    @Injectable()
    export class SharedService {

    //The current menu state
    private showMenu_ = false;

    //get the current menu state
    get showMenu() {
        return showMenu_;
    }

    //set the menu state
    set showMenu(state: boolean) {
        this.showMenu_ = state;
    }

    //toggle the menu
    public toggleMenu() {
        this.showMenu_ = !this.showMenu;
    }


}

Inject the service into appComponent so we can control the menu state with it.

appComponent.ts

import { SharedService } from 'PATH TO SHARED SERVICE';

...

constructor(public sharedService: SharedService){}

Set my-header to show/hide based on the state set in the sharedService.

appComponent.html

<my-header *ngIf="sharedService.showMenu"></my-header>

Inject the service into any other component/page to change the state of the menu. In this case ProductComponent.ts.

ProductComponent.ts

import { SharedService } from 'PATH TO SHARED SERVICE';

...

constructor(public sharedService: SharedService){}

ProductComponent.html

<div>
  <button (click)="sharedService.toggleMenu()">Click</button>
</div>

Or with BehavourSubject from service.

Create the BehaviorSubject in SharedService.

import { Injectable } from '@angular/core';

@Injectable()
export class SharedService {

//The current menu state
private showMenu_ = false;
private showMenu$: BehaviorSubject<boolean> = new 
BehaviorSubject(false);

//get a reference to showMenu$ for subscription
public menuState() {
    return showMenu$;
}

//Change menu state to show.
public showMenu(){
    this.showMenu_ = true;
    this.showMenu$.next(this.showMenu_);
}

//Change menu state to hide.
public hideMenu(){
    this.showMenu_ = false;
    this.showMenu$.next(this.showMenu_);
}

//Toggle menu state.
public toggleMenu(){
    this.showMenu_ = !this.showMenu;
    this.ShowMenu$.next(this.showMenu_);
}

//get the current menu state.
public getMenuState() {
    return this.showMenu$.getValue();
}

Inject the service into appComponent so we can subscribe to the menu state.

appComponent.ts

import { SharedService } from 'PATH TO SHARED SERVICE';

...

export class appComponent implements OnInit, OnDestroy {

//variable used to show/hide the menu.
public showMenu;

//reference to subscription so we can unsubscribe later.
private this.menuStateSub: Subscription;

constructor(public sharedService: SharedService){}

ngOnInit() {  
    //subscribe to the menuState BehaviorSubject
    this.menuStateSub = this.sharedService.menuState().subscribe((state)=>{
        this.showMenu = state;
    })
}

ngOnDestroy() {
    //unsubscribe before leaving the page
    this.menuStateSub.unsubscribe();
}

Set my-header to show/hide based on the state set in the sharedService.

appComponent.html

<my-header *ngIf="sharedService.showMenu"></my-header>

Finally inject the service where we need to control the menu state.

ProductComponent.ts

import { SharedService } from 'PATH TO SHARED SERVICE';

...

constructor(public sharedService: SharedService){}

and now we can use the service to toggle the state. ProductComponent.html

<div>
  <button (click)="sharedService.toggleMenu()">Click</button>
</div>
查看更多
登录 后发表回答