javascript - Angular - 作为输入传递函数
我有一个我动态创建的模态组件。
<div class="modal">
<div class="modal-body">
Test
</div>
<div class="modal-footer">
<button (click)="callbackFunction()">success</button>
<button>abort</button>
</div>
</div>
该组件有一个名为 Input callbackFunction 的输入,它是我想从父组件中调用的一个函数。
import {
Component,
Input,
OnInit,
QueryList,
ViewChildren
} from "@angular/core";
import { ModalService } from "../modal.service";
@Component({
selector: "app-modal",
templateUrl: "./modal.component.html",
styleUrls: ["./modal.component.css"]
})
export class ModalComponent implements OnInit {
@Input() callbackFunction: () => void;
constructor(private modalService: ModalService) {}
ngOnInit() {}
}
之后我创建了一个服务:
import {
ApplicationRef,
ComponentFactoryResolver,
ComponentRef,
Injectable,
Injector
} from "@angular/core";
import { ModalComponent } from "./modal/modal.component";
@Injectable()
export class ModalService {
dialogComponentRef: ComponentRef<ModalComponent>;
open(callbackFunction: any) {
const modalComponentFactory = this.cfResolver.resolveComponentFactory(ModalComponent);
const modalComponent = modalComponentFactory.create(this.injector);
modalComponent.instance.callbackFunction = callbackFunction;
this.dialogComponentRef = modalComponent;
document.body.appendChild(modalComponent.location.nativeElement);
this.appRef.attachView(modalComponent.hostView);
}
close() {
this.appRef.detachView(this.dialogComponentRef.hostView);
}
constructor(
private appRef: ApplicationRef,
private cfResolver: ComponentFactoryResolver,
private injector: Injector
) {}
}
在 componentFactoryResolver 之后,我将我的函数作为实例传递。
在我的父控制器中,我创建了一个函数
sayHello(
this.myService.doSomething();
}
然后我创建了一个用于打开模态框的函数
open(this.sayHello());
当我点击按钮并调用回调函数时,"this" 并不是指向父组件,而是指向 Modal 组件,且 sayHello 未定义。我该如何解决这种情况?
我不想使用 emit。
这是我的 Stackblitz:示例
答案#1
基本上有三种解决方案:Output + EventEmitter、@ViewChild 和 Subject
ViewChild 解决方案
- 当按钮定义在父组件上并且你想从子组件获取某些东西时,可以使用这个。
///////parent.component.ts
...
import { ChildComponent } from 'child/child.component';
...
export class ParentComponent {
@ViewChild(ChildComponent) childComponent: ChildComponent;
public buttonClick(): void {
let childResponse = this.childComponent.getValues();//will return '1234'
...
}
}
///////child.component.ts
export class ChildComponent {
valueInsideChild = '1234';
public getValues(): string {
return this.valueInsideChild;
}
}
Output + EventEmitter 解决方案
- 在这种情况下,子组件本身会向父组件发送某些内容(即按钮在子组件内部)
- 在 Stackblic 上的实现
//////parent.component.html
<child-selector
($buttonClicked)=clickAction($event)>
</child-selector>
//////parent.component.ts
...
export class ParentComponent {
public clickAction(value: string): void {
console.log(value);//will log 'something1234 when child button is clicked
}
}
//////child.component.ts
...
import { Output, Component, EventEmitter } from '@angular/core';
...
export class ChildComponent {
@Output() $buttonClicked = new EventEmitter<string>();
public click(): void {
this.$buttonClicked.emit('something1234');
}
}
//////child.component.html
<button (click)="click()">
主题
- 使用你的 modalService+subject+observables 进行界面响应
///app.component.ts
...
export class AppComponent {
...
open() {
//subscribe to the observable :)
this.modalService.open(this.sayHello).subscribe(response => {
alert(response.text);
});
}
...
}
///modal.component.html
...
<button (click)="click()">success</button>
...
///modal.component.ts
...
export class ModalComponent {
constructor(private modalService: ModalService) {}
...
public click(): void {
this.modalService.close({text: 'Hello World'});
}
}
///modal.service.ts
...
import { Subject, Observable } from 'rxjs';
...
export class ModalService {
...
private _modalResponse = new Subject<any>();
...
open(): Observable<any> {//this is your open function
...
return this._modalResponse.asObservable();//return an observable where the modal responses will be emitted
}
close(response: any): void {
//receives a value from the modal component when closing
this.appRef.detachView(this.dialogComponenRef.hostView);
this._modalResponse.next(response);//emit the response on the Observable return when open was called
}
}
答案#2
我建议你使用一个 Output 和一个 EventEmitter 来从子组件调用父组件的函数,Angular 文档提供了一个关于如何做的好例子。
https://angular.io/guide/inputs-outputs#sending-data-to-a-parent-component
