网站搜索

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