angular - Làm thế nào để gọi một phương thức từ một component khác sau khi view đã được tải đầy đủ?
Tôi đang sử dụng MatMenu từ Angular Material bên trong 'Header Component' của mình. Tôi chỉ cần mở Menu trong một số điều kiện nhất định. Tuy nhiên, phương pháp này chỉ hoạt động bên trong ngAfterViewInit(), sau khi view được tải.
export class HeaderComponent implements AfterViewInit {
@ViewChild('triggerCart') trigger: MatMenuTrigger;
ngAfterViewInit() {
this.openMenu();
}
openMenu() {
this.trigger.openMenu();
}
}<button mat-button
[matMenuTriggerFor]="shoppingCartMenu"
#triggerCart="matMenuTrigger"
(menuOpened)="isOpened($event)"
(mouseenter)="largeScreen ? triggerCart.openMenu() : ''">
</button>Tôi cần gọi phương thức này từ một thành phần khác, nhưng trigger của Menu lại không xác định bên ngoài ngAfterViewInit.
<button mat-stroked-button
(click)="someMethod()">
</button>export class ProductDetailComponent {
@ViewChild(HeaderComponent) header: HeaderComponent;
someMethod() {
this.header.openMenu();
}
}Làm thế nào tôi có thể thực hiện giao tiếp giữa các thành phần của mình sau khi Thành phần Header của tôi đã được tải?
Câu trả lời #1
Đây là một ví dụ về cách thực hiện (nhưng không nhất thiết là cách tốt nhất). Nó nhằm đưa ra ý tưởng về các tương tác giữa các thành phần.
StackBlitz
Thành phần sản phẩm
export class ProductComponent {
clickBehavior = new BehaviorSubject(null);
click() {
this.clickBehavior.next(1);
}
}
Đánh dấu giá sản phẩm
<my-header [openMenu]="clickBehavior"></my-header>
<div>
<button (click)="click()">Click</button>
</div>
Thành phần đầu trang
export class HeaderComponent implements AfterViewInit {
@ViewChild('trigger') trigger: MatMenuTrigger;
@Input() openMenu: Observable<any>;
ngAfterViewInit() {
this.openMenu.subscribe(value => {
if (value) {
this.trigger.openMenu();
}
});
}
}
Đánh dấu tiêu đề
<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>
Ý tưởng là kích hoạt một Input của component Header và việc này được thực hiện bằng cách sử dụng BehaviorSubject trong component Product.
Tham khảo :
- https://angular.io/guide/observables-in-angular
- https://thinkster.io/tutorials/learn-rxjs-observables/using-behaviorsubject-for-values-that-change-over-time
Câu trả lời #2
Bạn có thể đạt được điều này bằng cách sử dụng một dịch vụ chia sẻ và tiêm dịch vụ đó vào nơi cần thiết.
Thiết lập một dịch vụ chia sẻ, tôi đặt các phương thức để lấy, đặt và chuyển đổi trạng thái menu.
LƯU Ý: để làm cho điều này có hiệu ứng động vì nó sử dụng ngIf, bạn sẽ cần phải sử dụng các hiệu ứng động của Angular.
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;
}
}
Tiêm dịch vụ vào appComponent để chúng ta có thể điều khiển trạng thái menu bằng nó.
appComponent.ts
import { SharedService } from 'PATH TO SHARED SERVICE';
...
constructor(public sharedService: SharedService){}
Đặt my-header để hiển thị/ẩn dựa trên trạng thái được thiết lập trong sharedService.
appComponent.html
<my-header *ngIf="sharedService.showMenu"></my-header>
Tiêm dịch vụ vào bất kỳ thành phần/trang nào khác để thay đổi trạng thái của menu. Trong trường hợp này là 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>
Hoặc với BehaviorSubject từ dịch vụ.
Tạo BehaviorSubject trong 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();
}
Tiêm dịch vụ vào appComponent để chúng ta có thể đăng ký trạng thái menu.
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();
}
Đặt my-header để hiển thị/ẩn dựa trên trạng thái được thiết lập trong sharedService.
appComponent.html
<my-header *ngIf="sharedService.showMenu"></my-header>
Cuối cùng tiêm dịch vụ vào nơi chúng ta cần kiểm soát trạng thái menu.
ProductComponent.ts
import { SharedService } from 'PATH TO SHARED SERVICE';
...
constructor(public sharedService: SharedService){}
và bây giờ chúng ta có thể sử dụng dịch vụ để chuyển đổi trạng thái. ProductComponent.html
<div>
<button (click)="sharedService.toggleMenu()">Click</button>
</div>
