4

我正在尝试实现一个基本的(非常基本的)模式实现。我有一个ModalService和一个ModalComponent

ModalService创建一个实例并使用@angular/cdk/portal 将其ModalComponent注入到页面中。

我可以让模态显示得很好:-)

ModalComponent有一个我希望订阅的 Observable 属性,以便ModalService在模式中单击“关闭”按钮时,可以发出一个值并且ModalService可以关闭模​​式。

但是,当组件发出值时,服务不会对其进行操作。从服务端看,我好像订阅了,但从组件端看,它显示了 0 个观察者。

我想也许我可以使用一个典型的@Output()EventEmitter,但我不确定在模态类中将其连接起来,因为子元素最初不存在。

我在想也许我的组件引用不太正确(也许我有 2 个不同的?)。我正在尝试从这个答案中提出建议

任何想法我做错了什么?

服务

export class ModalService {

    private modalPortal: ComponentPortal<any>;
    private bodyPortalHost: DomPortalHost;

    constructor(private componentFactoryResolver: ComponentFactoryResolver,
                private appRef: ApplicationRef,
                private injector: Injector) {
    }

    showModal(modalName: string) {

        // set up the portal and portal host
        this.modalPortal = new ComponentPortal(ModalComponent);
        this.bodyPortalHost = new DomPortalHost(
            document.body,
            this.componentFactoryResolver,
            this.appRef,
            this.injector);

        // display the component in the page
        let componentRef = this.bodyPortalHost.attach(this.modalPortal);


        // listen for modal's close event
        componentRef.instance.onModalClose().subscribe(() => {
            console.log('I will be very happy if this this gets called, but it never ever does');
            this.closeModal();
        });

        // console.log(componentRef.instance.onModalClose()) shows 1 subscriber.
    }

    closeModal() {
        this.bodyPortalHost.detach();
    }
}

零件

export class ModalComponent {

    private modalClose: Subject<any> = new Subject();

    onModalClose(): Observable<any> {
        return this.modalClose.asObservable();
    }

    closeModal() {
        // console.log(this.onModalClose()) **shows zero observers**   :-(
        this.modalClose.next();
        this.modalClose.complete();
    }
}

另外,如果我碰巧问错了问题,这意味着有更好的整体方法,我愿意接受建议。:-)

谢谢!

4

1 回答 1

2

这段代码对我来说只需要很少的改动,所以我很困惑你的问题是什么。首先,我使用 Angular CLI 创建了一个项目ng new然后我按照他们网站上的说明安装了 ng 材料。

我创建了一个与您的相同的模态服务:

    import {ApplicationRef, ComponentFactoryResolver, Injectable, Injector} from '@angular/core';
import {DomPortalHost, ComponentPortal} from "@angular/cdk/portal";
import {ModalComponent} from "./modal/modal.component";

@Injectable({
  providedIn: 'root'
})
export class ModalService {

  private modalPortal: ComponentPortal<any>;
  private bodyPortalHost: DomPortalHost;

  constructor(private componentFactoryResolver: ComponentFactoryResolver,
              private appRef: ApplicationRef,
              private injector: Injector) {
  }

  showModal(modalName: string) {

    // set up the portal and portal host
    this.modalPortal = new ComponentPortal(ModalComponent);
    this.bodyPortalHost = new DomPortalHost(
      document.body,
      this.componentFactoryResolver,
      this.appRef,
      this.injector);

    // display the component in the page
    let componentRef = this.bodyPortalHost.attach(this.modalPortal);


    // listen for modal's close event
    componentRef.instance.onModalClose().subscribe(() => {
      console.log('I will be very happy if this this gets called, but it never ever does');
      this.closeModal();
    });

    // console.log(componentRef.instance.onModalClose()) shows 1 subscriber.
  }

  closeModal() {
    this.bodyPortalHost.detach();
  }
}

我创建了一个模态组件。TypeScript 和你的一样:

import { Component, OnInit } from '@angular/core';
import {Observable, Subject} from "rxjs/index";

@Component({
  selector: 'app-modal',
  templateUrl: './modal.component.html',
  styleUrls: ['./modal.component.css']
})
export class ModalComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

  private modalClose: Subject<any> = new Subject();

  onModalClose(): Observable<any> {
    return this.modalClose.asObservable();
  }

  closeModal() {
    // console.log(this.onModalClose()) **shows zero observers**   :-(
    this.modalClose.next();
    this.modalClose.complete();
  }

}

您没有为我们提供 HTML 模型,但这是我使用的:

<p>
  modal works!
</p>
<button (click)="closeModal()">Close Modal</button>

这是我的 app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';

import { AppComponent } from './app.component';
import {ModalService} from "src/app/modal.service";
import { ModalComponent } from './modal/modal.component';

@NgModule({
  declarations: [
    AppComponent,
    ModalComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule
  ],
  providers: [ModalService],
  bootstrap: [AppComponent],
  entryComponents: [ModalComponent]
})
export class AppModule { }

注意我在 entryComponents 和 ModalService 中定义了 ModalComponent 作为提供者。

app.component HTML:

<button (click)="showModal()">Show Modal</button>

和 app.component 打字稿:

import { Component } from '@angular/core';
import {ModalService} from "./modal.service";
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  constructor(public modalService: ModalService){}

  showModal(){
       this.modalService.showModal("This is the modal name");
  }

}

我将 ModalService 注入构造函数并调用您的 showModal 方法以响应主应用程序中的按钮单击。

加载应用程序: 初始应用加载

单击按钮,将显示模式。它看起来不像模态,但这可能是因为缺少样式:

显示模态的应用程序

现在单击模态框内的关闭按钮:

模态关闭

您会看到模式消失了,控制台输出显示您的消息。

这篇文章是否可以帮助您找到您错过的花絮?


要补充的一件事。如果您想将数据从模态发送到调用它的组件,请更改模态组件的 closeModal 方法:

  closeModal() {
    // console.log(this.onModalClose()) **shows zero observers**   :-(
    this.modalClose.next('Your Data Here, it can be an object if need be');
    this.modalClose.complete();
  }

并且您的模态服务可以访问onModalClose().subscribe()方法中的数据:

componentRef.instance.onModalClose().subscribe((results) => {
  console.log(results);
  console.log('I will be very happy if this this gets called, but it never ever does');
  this.closeModal();
});
于 2018-10-11T12:56:33.550 回答