From 293b5426b2aacb1f1e5ffeb91051658487720f81 Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Tue, 15 Oct 2024 15:45:48 -0300 Subject: [PATCH] feat: allow custom injector in dialogs and handle deprecations --- .../angular/src/lib/cdk/dialog/dialog-config.ts | 12 ++++++++++-- .../angular/src/lib/cdk/dialog/dialog-services.ts | 2 +- .../angular/src/lib/cdk/dialog/native-modal-ref.ts | 13 ++++++++----- .../src/lib/cdk/portal/nsdom-portal-outlet.ts | 14 +++++++++----- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/packages/angular/src/lib/cdk/dialog/dialog-config.ts b/packages/angular/src/lib/cdk/dialog/dialog-config.ts index 99d56b5..38468c2 100644 --- a/packages/angular/src/lib/cdk/dialog/dialog-config.ts +++ b/packages/angular/src/lib/cdk/dialog/dialog-config.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import { ViewContainerRef, ComponentFactoryResolver } from '@angular/core'; +import { ViewContainerRef, ComponentFactoryResolver, Injector } from '@angular/core'; import { ShowModalOptions, View } from '@nativescript/core'; export type NativeShowModalOptions = Partial>; @@ -22,6 +22,12 @@ export class NativeDialogConfig { */ viewContainerRef?: ViewContainerRef; + /** + * Injector used for the instantiation of the component to be attached. If provided, + * takes precedence over the injector indirectly provided by `ViewContainerRef`. + */ + injector?: Injector; + /** Where to render the actual dialog in. By default it renders using the native view of the ViewContainerRef */ renderIn?: 'root' | 'viewContainerRef' | View = 'viewContainerRef'; @@ -44,7 +50,9 @@ export class NativeDialogConfig { */ closeOnNavigation?: boolean = true; - /** Alternate `ComponentFactoryResolver` to use when resolving the associated component. */ + /** Alternate `ComponentFactoryResolver` to use when resolving the associated component. + * @deprecated + */ componentFactoryResolver?: ComponentFactoryResolver; nativeOptions?: NativeShowModalOptions = {}; diff --git a/packages/angular/src/lib/cdk/dialog/dialog-services.ts b/packages/angular/src/lib/cdk/dialog/dialog-services.ts index 4d37a99..c64800c 100644 --- a/packages/angular/src/lib/cdk/dialog/dialog-services.ts +++ b/packages/angular/src/lib/cdk/dialog/dialog-services.ts @@ -169,7 +169,7 @@ export abstract class _NativeDialogBase implements OnD * @returns The custom injector that can be used inside the dialog. */ private _createInjector(config: NativeDialogConfig, dialogRef: NativeDialogRef): Injector { - const userInjector = config && config.viewContainerRef && config.viewContainerRef.injector; + const userInjector = config && (config.injector || (config.viewContainerRef && config.viewContainerRef.injector)); // The dialog container should be provided as the dialog container and the dialog's // content are created out of the same `ViewContainerRef` and as such, are siblings diff --git a/packages/angular/src/lib/cdk/dialog/native-modal-ref.ts b/packages/angular/src/lib/cdk/dialog/native-modal-ref.ts index 01748f6..939fab8 100644 --- a/packages/angular/src/lib/cdk/dialog/native-modal-ref.ts +++ b/packages/angular/src/lib/cdk/dialog/native-modal-ref.ts @@ -1,4 +1,4 @@ -import { ApplicationRef, ComponentFactoryResolver, ComponentRef, EmbeddedViewRef, Injector, Optional, ViewContainerRef } from '@angular/core'; +import { ApplicationRef, ComponentFactoryResolver, ComponentRef, createComponent, EmbeddedViewRef, Injector, Optional, ViewContainerRef } from '@angular/core'; import { Application, ContentView, Frame, View } from '@nativescript/core'; import { fromEvent, Subject } from 'rxjs'; import { take } from 'rxjs/operators'; @@ -62,12 +62,15 @@ export class NativeModalRef { } _generateDetachedContainer(vcRef?: ViewContainerRef) { - const detachedFactory = (this._config.componentFactoryResolver || this._injector.get(ComponentFactoryResolver)).resolveComponentFactory(DetachedLoader); if (vcRef) { - this.detachedLoaderRef = vcRef.createComponent(detachedFactory); + this.detachedLoaderRef = vcRef.createComponent(DetachedLoader); } else { - this.detachedLoaderRef = detachedFactory.create(this._config.viewContainerRef?.injector || this._injector); - this._injector.get(ApplicationRef).attachView(this.detachedLoaderRef.hostView); + const appRef = this._injector.get(ApplicationRef); + this.detachedLoaderRef = createComponent(DetachedLoader, { + environmentInjector: appRef.injector, + elementInjector: this._config.injector || this._config.viewContainerRef?.injector || this._injector, + }); + appRef.attachView(this.detachedLoaderRef.hostView); } this.detachedLoaderRef.changeDetectorRef.detectChanges(); } diff --git a/packages/angular/src/lib/cdk/portal/nsdom-portal-outlet.ts b/packages/angular/src/lib/cdk/portal/nsdom-portal-outlet.ts index c72ff7a..e629710 100644 --- a/packages/angular/src/lib/cdk/portal/nsdom-portal-outlet.ts +++ b/packages/angular/src/lib/cdk/portal/nsdom-portal-outlet.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import { ComponentFactoryResolver, ComponentRef, EmbeddedViewRef, ApplicationRef, Injector, Renderer2, Optional } from '@angular/core'; +import { ComponentFactoryResolver, ComponentRef, EmbeddedViewRef, ApplicationRef, Injector, Renderer2, Optional, createComponent } from '@angular/core'; import { View } from '@nativescript/core'; import { CommentNode } from '../../views/invisible-nodes'; import { ViewUtil } from '../../view-util'; @@ -36,8 +36,6 @@ export class NativeScriptDomPortalOutlet extends BasePortalOutlet { * @returns Reference to the created component. */ attachComponentPortal(portal: ComponentPortal): ComponentRef { - const resolver = portal.componentFactoryResolver || this._componentFactoryResolver; - const componentFactory = resolver.resolveComponentFactory(portal.component); let componentRef: ComponentRef; // If the portal specifies a ViewContainerRef, we will use that as the attachment point @@ -45,11 +43,17 @@ export class NativeScriptDomPortalOutlet extends BasePortalOutlet { // When the ViewContainerRef is missing, we use the factory to create the component directly // and then manually attach the view to the application. if (portal.viewContainerRef) { - componentRef = portal.viewContainerRef.createComponent(componentFactory, portal.viewContainerRef.length, portal.injector || portal.viewContainerRef.injector); + componentRef = portal.viewContainerRef.createComponent(portal.component, { + index: portal.viewContainerRef.length, + injector: portal.injector || portal.viewContainerRef.injector, + }); this.setDisposeFn(() => componentRef.destroy()); } else { - componentRef = componentFactory.create(portal.injector || this._defaultInjector); + componentRef = createComponent(portal.component, { + elementInjector: portal.injector || this._defaultInjector || Injector.NULL, + environmentInjector: this._appRef.injector, + }); this._appRef.attachView(componentRef.hostView); this.setDisposeFn(() => { this._appRef.detachView(componentRef.hostView);