Skip to content

Commit

Permalink
feat: allow custom injector in dialogs and handle deprecations
Browse files Browse the repository at this point in the history
  • Loading branch information
edusperoni committed Oct 18, 2024
1 parent 88f1254 commit 293b542
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 13 deletions.
12 changes: 10 additions & 2 deletions packages/angular/src/lib/cdk/dialog/dialog-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Omit<ShowModalOptions, 'cancelable' | 'closeCallback'>>;
Expand All @@ -22,6 +22,12 @@ export class NativeDialogConfig<D = any> {
*/
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';

Expand All @@ -44,7 +50,9 @@ export class NativeDialogConfig<D = any> {
*/
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 = {};
Expand Down
2 changes: 1 addition & 1 deletion packages/angular/src/lib/cdk/dialog/dialog-services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ export abstract class _NativeDialogBase<C extends NativeModalRef> implements OnD
* @returns The custom injector that can be used inside the dialog.
*/
private _createInjector<T>(config: NativeDialogConfig, dialogRef: NativeDialogRef<T>): 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
Expand Down
13 changes: 8 additions & 5 deletions packages/angular/src/lib/cdk/dialog/native-modal-ref.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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();
}
Expand Down
14 changes: 9 additions & 5 deletions packages/angular/src/lib/cdk/portal/nsdom-portal-outlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -36,20 +36,24 @@ export class NativeScriptDomPortalOutlet extends BasePortalOutlet {
* @returns Reference to the created component.
*/
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
const resolver = portal.componentFactoryResolver || this._componentFactoryResolver;
const componentFactory = resolver.resolveComponentFactory(portal.component);
let componentRef: ComponentRef<T>;

// If the portal specifies a ViewContainerRef, we will use that as the attachment point
// for the component (in terms of Angular's component tree, not rendering).
// 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);
Expand Down

0 comments on commit 293b542

Please sign in to comment.