如何订阅通过@angular/cdk/portal 注入的组件的 Observable? [英] How to subscribe to Observable of Component injected via @angular/cdk/portal?

查看:17
本文介绍了如何订阅通过@angular/cdk/portal 注入的组件的 Observable?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

ModalComponent 有一个 Observable 属性,我希望 ModalService 订阅它,这样当在模态中单击关闭"按钮时,可以发出一个值并且 ModalService 可以关闭模​​态.

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

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

我在想我的组件引用可能不太正确(也许我有 2 个不同的组件?).我正在尝试来自

点击按钮,模态出现.它看起来不像模态,但这可能是因为缺少样式:

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

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

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

<小时>

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

 closeModal() {//console.log(this.onModalClose()) **显示零观察者** :-(this.modalClose.next('你的数据在这里,如果需要它可以是一个对象');this.modalClose.complete();}

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

componentRef.instance.onModalClose().subscribe((results) => {控制台日志(结果);console.log('如果这个被调用,我会很高兴,但它从来没有');this.closeModal();});

I'm trying to implement a basic (very basic) modal implementation. I've got a ModalService and a ModalComponent.

The ModalService creates an instance of the ModalComponent and injects it into the page using the @angular/cdk/portal.

I can get the modal to display just fine :-)

The ModalComponent has an Observable property that I want the ModalService to subscribe to so that when the 'close' button is clicked within the modal, a value can be emitted and the ModalService can close the modal.

However, when the component emits the value, the Service is not acting on it. From the Service side, it looks like I'm subscribed, but from the Component side, it shows 0 observers.

I thought maybe I could use a typical @Output() EventEmitter, but I'm not sure to hook that up since the in the modal class, since the child element doesn't exist initially.

I'm thinking maybe my component reference is not quite right (maybe I have 2 different ones?). I'm trying suggestion from this answer

Any ideas what I'm doing wrong?

Service

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();
    }
}

Component

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();
    }
}

Also, if I happen to be asking the wrong question, meaning there's a better overall approach, I'm open to suggestions. :-)

Thanks!

解决方案

This code works for me with very few changes, so I'm confused as to what your problem is. First I created a project with the Angular CLI using ng new. Then I installed ng material using the instructions on their site.

I created a modal service which is identical to yours:

    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();
  }
}

I created a modal component. The TypeScript is the same as yours:

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();
  }

}

You didn't give us a model for the HTML, but this is what I used:

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

Here is my 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 { }

Note I Defined the ModalComponent in the entryComponents and the ModalService as a provider.

The app.component HTML:

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

And the app.component typescript:

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");
  }

}

I injected the ModalService into the constructor and called your showModal method in response to the button click in the main app.

Load the app:

Click the button and the modal shows up. It doesn't look like a modal, but that could be because of missing styling :

Now click the close button inside the modal:

You see the modal is gone and the console output displays your message.

Does this post help you find the tidbit you missed?


One thing to add. If you want to send data out of your modal to the component that called it, ust change your modalComponent's closeModal method:

  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();
  }

And your modal service can access the data in the onModalClose().subscribe() method:

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();
});

这篇关于如何订阅通过@angular/cdk/portal 注入的组件的 Observable?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆