Skip to content

Commit

Permalink
fix(modal): provide NgbModal at the correct level (#4464)
Browse files Browse the repository at this point in the history
Provides `NgbModal` at the `NgbModalModule` level as well as at the 'root' level.
Provides environment injector based on the `contentInjector` and not the `appRef.injector` when using component as modal content.

Fixes #4447
  • Loading branch information
maxokorokov committed Jan 9, 2023
1 parent 7f2146d commit 8ac01c2
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 5 deletions.
40 changes: 40 additions & 0 deletions src/modal/modal-lazy-module.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Component, inject, Injectable, NgModule, OnDestroy } from '@angular/core';
import { NgbModal } from './modal';
import { NgbModalModule } from './modal.module';
import { RouterModule } from '@angular/router';

@Injectable()
class LazyService {
get text() {
return 'lazy modal';
}
}

@Component({ template: '{{ lazyService.text }}' })
class LazyModalContent {
constructor(public lazyService: LazyService) {}
}

@Component({ template: 'child' })
class LazyComponent implements OnDestroy {
private _ref = inject(NgbModal).open(LazyModalContent);

ngOnDestroy() {
this._ref.close();
}
}

@NgModule({
declarations: [LazyComponent, LazyModalContent],
providers: [LazyService],
imports: [
NgbModalModule,
RouterModule.forChild([
{
path: '',
component: LazyComponent,
},
]),
],
})
export default class LazyModule {}
13 changes: 10 additions & 3 deletions src/modal/modal-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
ApplicationRef,
ComponentRef,
createComponent,
EnvironmentInjector,
EventEmitter,
Inject,
Injectable,
Expand Down Expand Up @@ -50,6 +51,7 @@ export class NgbModalStack {
constructor(
private _applicationRef: ApplicationRef,
private _injector: Injector,
private _environmentInjector: EnvironmentInjector,
@Inject(DOCUMENT) private _document: any,
private _scrollBar: ScrollBar,
private _rendererFactory: RendererFactory2,
Expand Down Expand Up @@ -96,7 +98,10 @@ export class NgbModalStack {
this._hideScrollBar();

const activeModal = new NgbActiveModal();
const contentRef = this._getContentRef(options.injector || contentInjector, content, activeModal, options);

contentInjector = options.injector || contentInjector;
const environmentInjector = contentInjector.get(EnvironmentInjector, null) || this._environmentInjector;
const contentRef = this._getContentRef(contentInjector, environmentInjector, content, activeModal, options);

let backdropCmptRef: ComponentRef<NgbModalBackdrop> | undefined =
options.backdrop !== false ? this._attachBackdrop(containerEl) : undefined;
Expand Down Expand Up @@ -190,6 +195,7 @@ export class NgbModalStack {

private _getContentRef(
contentInjector: Injector,
environmentInjector: EnvironmentInjector,
content: Type<any> | TemplateRef<any> | string,
activeModal: NgbActiveModal,
options: NgbModalOptions,
Expand All @@ -201,7 +207,7 @@ export class NgbModalStack {
} else if (isString(content)) {
return this._createFromString(content);
} else {
return this._createFromComponent(contentInjector, content, activeModal, options);
return this._createFromComponent(contentInjector, environmentInjector, content, activeModal, options);
}
}

Expand All @@ -227,6 +233,7 @@ export class NgbModalStack {

private _createFromComponent(
contentInjector: Injector,
environmentInjector: EnvironmentInjector,
componentType: Type<any>,
context: NgbActiveModal,
options: NgbModalOptions,
Expand All @@ -236,7 +243,7 @@ export class NgbModalStack {
parent: contentInjector,
});
const componentRef = createComponent(componentType, {
environmentInjector: this._applicationRef.injector,
environmentInjector,
elementInjector,
});
const componentNativeEl = componentRef.location.nativeElement;
Expand Down
4 changes: 3 additions & 1 deletion src/modal/modal.module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { NgModule } from '@angular/core';

import { NgbModal } from './modal';

export { NgbModal } from './modal';
export { NgbModalConfig, NgbModalOptions } from './modal-config';
export { NgbModalRef, NgbActiveModal } from './modal-ref';
export { ModalDismissReasons } from './modal-dismiss-reasons';

@NgModule({})
@NgModule({ providers: [NgbModal] })
export class NgbModalModule {}
41 changes: 40 additions & 1 deletion src/modal/modal.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Component, Injectable, Injector, OnDestroy, ViewChild } from '@angular/core';
import { NgIf } from '@angular/common';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { Router } from '@angular/router';
import { NgbModalConfig, NgbModalOptions } from './modal-config';
import { NgbActiveModal, NgbModal, NgbModalRef } from './modal.module';
import { NgbActiveModal, NgbModal, NgbModalModule, NgbModalRef } from './modal.module';
import { createKeyEvent, isBrowserVisible } from '../test/common';
import { NgbConfig } from '..';
import { NgbConfigAnimation } from '../test/ngb-config-animation';
Expand Down Expand Up @@ -1199,6 +1201,43 @@ describe('ngb-modal', () => {
});
});
}

describe('Lazy loading', () => {
@Component({ template: '<router-outlet></router-outlet>' })
class AppComponent {}

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [AppComponent],
imports: [
NgbModalModule,
RouterTestingModule.withRoutes([
{
path: 'lazy',
loadChildren: () => import('./modal-lazy-module.spec'),
},
]),
],
});
});

it('should use correct injectors', fakeAsync(() => {
const router = TestBed.inject(Router);

const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();

// opening by navigating
router.navigate(['lazy']);
tick();
fixture.detectChanges();
expect(fixture.nativeElement).toHaveModal('lazy modal');

// closing by navigating away
router.navigate(['']);
tick();
}));
});
});

@Component({ selector: 'custom-injector-cmpt', standalone: true, template: 'Some content' })
Expand Down

0 comments on commit 8ac01c2

Please sign in to comment.