Skip to content

Commit

Permalink
fix(angular): fix change detection on modal when using a TemplateRef (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
tiagogviegas committed Aug 18, 2023
1 parent cadc503 commit e11b367
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 31 deletions.
3 changes: 2 additions & 1 deletion packages/angular/src/modal/modal.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
* LICENSE file in the root directory of this source tree.
*/

import { TemplateRef, Type } from '@angular/core';
import { ModalConfig as IxModalConfig } from '@siemens/ix';

export type ModalConfig<TDATA = any> = Omit<IxModalConfig, 'content'> & {
content: any;
content: TemplateRef<unknown> | Type<unknown>;
data?: TDATA;
};
15 changes: 14 additions & 1 deletion packages/angular/src/modal/modal.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,18 @@ jest.mock('@siemens/ix', () => ({
}));

test('should create modal by templateRef', () => {
const appRefMock = {
attachView: jest.fn(),
};
const createEmbeddedViewMock = jest.fn((_: { $implicit: any }) => ({
rootNodes: [{}],
detectChanges: jest.fn(),
}));
const modalService = new ModalService({} as any, {} as any, {} as any);
const modalService = new ModalService(
appRefMock as any,
{} as any,
{} as any
);
modalService.open({
content: {
createEmbeddedView: createEmbeddedViewMock,
Expand All @@ -46,6 +53,7 @@ test('should create modal by templateRef', () => {
dismiss: expect.any(Function),
},
});
expect(appRefMock.attachView).toHaveBeenCalled();
});

test('should create modal by component typ', async () => {
Expand All @@ -58,6 +66,11 @@ test('should create modal by component typ', async () => {
rootNodes: [jest.fn()],
detectChanges: jest.fn(),
},
injector: {
get: jest.fn(() => ({
nativeElement: {}
})),
},
})),
};
const componentFactoryMock = {
Expand Down
59 changes: 32 additions & 27 deletions packages/angular/src/modal/modal.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
import {
ApplicationRef,
ComponentFactoryResolver,
EmbeddedViewRef,
ElementRef,
Injectable,
Injector,
TemplateRef,
Type,
ViewRef,
} from '@angular/core';
import { closeModal, dismissModal, showModal } from '@siemens/ix';
import { InternalIxActiveModal, IxActiveModal } from './modal-ref';
Expand Down Expand Up @@ -43,10 +45,15 @@ export class ModalService {
};

if (config.content instanceof Type) {
return this.createContentByComponentType<TData, TReason>(config, context);
return this.createContentByComponentType<TData, TReason>(
config.content,
config,
context
);
}

const modalInstance = await this.createContentByTemplateRef<TData, TReason>(
config.content,
config,
context
);
Expand All @@ -55,14 +62,14 @@ export class ModalService {
}

private async createContentByComponentType<TData = any, TReason = any>(
componentType: Type<unknown>,
config: ModalConfig<TData>,
context: ModalContext<TData>
) {
const activeModal = new InternalIxActiveModal<TData>(context.data);

const modalFactory = this.componentFactoryResolver.resolveComponentFactory(
config.content
);
const modalFactory =
this.componentFactoryResolver.resolveComponentFactory(componentType);

const modalInjector = Injector.create({
providers: [
Expand All @@ -77,10 +84,12 @@ export class ModalService {
const instance = modalFactory.create(modalInjector);
this.appRef.attachView(instance.hostView);

const embeddedView = instance.hostView as EmbeddedViewRef<any>;
const element = instance.injector.get(ElementRef);

const modalInstance = await this.createModalInstance<TData, TReason>(
context,
embeddedView,
element.nativeElement,
instance.hostView,
config
);

Expand All @@ -90,55 +99,51 @@ export class ModalService {
}

private async createContentByTemplateRef<TData = any, TReason = any>(
templateRef: TemplateRef<unknown>,
config: ModalConfig<TData>,
context: {
close: ((result: any) => void) | null;
dismiss: ((result?: any) => void) | null;
data?: TData | undefined;
}
context: ModalContext<TData>
) {
const embeddedView = config.content.createEmbeddedView({
const embeddedView = templateRef.createEmbeddedView({
$implicit: context,
});

this.appRef.attachView(embeddedView);

return await this.createModalInstance<TData, TReason>(
context,
embeddedView.rootNodes[0],
embeddedView,
config
);
}

private async createModalInstance<TData = any, TReason = any>(
context: {
close: ((result: any) => void) | null;
dismiss: ((result?: any) => void) | null;
data?: TData | undefined;
},
embeddedView: EmbeddedViewRef<any>,
context: ModalContext<TData>,
htmlElement: HTMLElement,
viewRef: ViewRef,
config: ModalConfig<TData>
) {
const node = embeddedView.rootNodes[0];

context.close = (result: any) => {
closeModal(node, result);
closeModal(htmlElement, result);
};

context.dismiss = (result?: any) => {
dismissModal(node, result);
dismissModal(htmlElement, result);
};

embeddedView.detectChanges();
viewRef.detectChanges();

const modalInstance = await showModal<TReason>({
...config,
content: node,
content: htmlElement,
});

modalInstance.onClose.once(() => {
embeddedView.destroy();
viewRef.destroy();
});

modalInstance.onDismiss.once(() => {
embeddedView.destroy();
viewRef.destroy();
});
return modalInstance;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/documentation/docs/controls/modal.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import ApiModalInstanceAngular from './\_modal/angular/modal-instance.html.md'
import ApiModalConfigReact from './\_modal/react/modal-config.md'
import ApiModalRefReact from './\_modal/react/modal-ref.html.md'

import ModalConfig from './../auto-generated/utils/core/ModalConfig.md'
import ModalInstance from './../auto-generated/utils/core/ModalInstance.md'
import ModalConfig from './../auto-generated/utils/ModalConfig.md'
import ModalInstance from './../auto-generated/utils/ModalInstance.md'

import SourceReactLoading from './../auto-generated/previews/react/loading.md'
import SourceReactMessage from './../auto-generated/previews/react/message.md'
Expand Down

0 comments on commit e11b367

Please sign in to comment.