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

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

问题描述

我正在尝试实现基本(非常基本)的模式实现.我有一个ModalServiceModalComponent.

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

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

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 :-)

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

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.

但是,当组件发出该值时,服务不会对其执行操作.从服务方面看,我已经订阅了,但是从组件方面看,它显示了0个观察者.

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.

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

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.

我在想也许我的组件参考不太正确(也许我有2种不同的参考?).我正在尝试从此答案

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?

服务

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

此外,如果我碰巧问错了问题,这意味着有更好的整体方法,我欢迎您提出建议. :-)

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

谢谢!

推荐答案

这段代码对我来说几乎没有变化,所以我对您的问题感到困惑.首先,我使用ng new使用Angular CLI创建了一个项目.然后,我使用网站上的说明安装了ng材料.

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

我创建了一个模态组件. TypeScript与您的相同:

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

}

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

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>

这是我的app.module.ts:

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 { }

请注意,我在entryComponents和ModalService中将ModalComponent定义为提供程序.

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

app.component HTML:

The app.component HTML:

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

和app.component打字稿:

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

}

我将ModalService注入到构造函数中,并响应主应用程序中的按钮单击调用了showModal方法.

I injected the ModalService into the constructor and called your showModal method in response to the button click in the main 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?

要添加的一件事.如果要将数据从模态中发送到调用它的组件,则必须更改modalComponent的closeModal方法:

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

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

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天全站免登陆