如何订阅通过@angular/cdk/portal注入的Component的Observable?
How to subscribe to Observable of Component injected via @angular/cdk/portal?
我正在尝试实现一个基本的(非常基本的)模态实现。我有一个 ModalService
和一个 ModalComponent
。
ModalService
创建了一个 ModalComponent
的实例,并使用 @angular/cdk/portal.
将其注入到页面中
我可以让模态显示得很好:-)
ModalComponent
有一个 Observable 属性,我希望 ModalService
订阅它,这样当 'close' 按钮在模式中被点击时,一个值可以被发射并且 ModalService
可以关闭模式。
但是,当组件发出值时,服务不会对其进行操作。从服务端看,我好像订阅了,但从组件端看,它显示 0 个观察者。
我想也许我可以使用典型的 @Output()
EventEmitter,但我不确定是否将其连接起来,因为在模态 class 中,因为子元素最初不存在.
我在想我的组件参考可能不太正确(也许我有 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();
}
}
此外,如果我碰巧问错了问题,这意味着有更好的整体方法,我愿意接受建议。 :-)
谢谢!
这段代码对我来说只需要很少的改动,所以我很困惑你的问题是什么。首先,我使用 ng new
通过 Angular CLI 创建了一个项目。然后我使用 instructions on their site.
安装了 ng material
我创建了一个与您的相同的模态服务:
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 中定义了 ModalComponent 并将 ModalService 定义为提供者。
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 方法以响应主应用程序中的按钮单击。
加载应用:
点击按钮,模式就会出现。它看起来不像模态,但这可能是因为缺少样式:
现在单击模式内的关闭按钮:
您看到模式消失了,控制台输出显示了您的消息。
这个 post 可以帮助您找到错过的珍闻吗?
要补充一点。如果您想将数据从您的模式发送到调用它的组件,只需更改您的 modalComponent 的 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();
});
我正在尝试实现一个基本的(非常基本的)模态实现。我有一个 ModalService
和一个 ModalComponent
。
ModalService
创建了一个 ModalComponent
的实例,并使用 @angular/cdk/portal.
我可以让模态显示得很好:-)
ModalComponent
有一个 Observable 属性,我希望 ModalService
订阅它,这样当 'close' 按钮在模式中被点击时,一个值可以被发射并且 ModalService
可以关闭模式。
但是,当组件发出值时,服务不会对其进行操作。从服务端看,我好像订阅了,但从组件端看,它显示 0 个观察者。
我想也许我可以使用典型的 @Output()
EventEmitter,但我不确定是否将其连接起来,因为在模态 class 中,因为子元素最初不存在.
我在想我的组件参考可能不太正确(也许我有 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();
}
}
此外,如果我碰巧问错了问题,这意味着有更好的整体方法,我愿意接受建议。 :-)
谢谢!
这段代码对我来说只需要很少的改动,所以我很困惑你的问题是什么。首先,我使用 ng new
通过 Angular CLI 创建了一个项目。然后我使用 instructions on their site.
我创建了一个与您的相同的模态服务:
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 中定义了 ModalComponent 并将 ModalService 定义为提供者。
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 方法以响应主应用程序中的按钮单击。
加载应用:
点击按钮,模式就会出现。它看起来不像模态,但这可能是因为缺少样式:
现在单击模式内的关闭按钮:
您看到模式消失了,控制台输出显示了您的消息。
这个 post 可以帮助您找到错过的珍闻吗?
要补充一点。如果您想将数据从您的模式发送到调用它的组件,只需更改您的 modalComponent 的 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();
});