Skip to content

Commit 609da58

Browse files
authored
Merge pull request #2534 from Akshat55/component-factory-resolver
fix: Update dynamic rendering strategy to use ONLY ComponentRef
2 parents 2d72137 + 3a09015 commit 609da58

File tree

8 files changed

+47
-86
lines changed

8 files changed

+47
-86
lines changed

src/dialog/dialog.directive.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export class DialogDirective implements OnInit, OnDestroy, OnChanges {
143143
// set the config object (this can [and should!] be added to in child classes depending on what they need)
144144
this.dialogConfig = {
145145
title: this.title,
146-
content: this.ibmDialog,
146+
content: this.cdsDialog,
147147
placement: this.placement,
148148
parentRef: this.elementRef,
149149
gap: this.gap,
@@ -247,12 +247,12 @@ export class DialogDirective implements OnInit, OnDestroy, OnChanges {
247247
* Helper method to call dialogService 'open'.
248248
* - Enforce accessibility by updating an aria attr for nativeElement.
249249
*/
250-
open() {
250+
open(component?) {
251251
// don't allow dialogs to be opened if they're already open
252252
if (this.dialogRef || this.disabled) { return; }
253253

254254
// actually open the dialog, emit events, and set the open state
255-
this.dialogRef = this.dialogService.open(this.viewContainerRef, this.dialogConfig);
255+
this.dialogRef = this.dialogService.open(this.viewContainerRef, this.dialogConfig, component);
256256
this.isOpen = true;
257257
this.onOpen.emit();
258258
this.isOpenChange.emit(true);

src/dialog/dialog.service.ts

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import {
22
Injector,
33
ComponentRef,
4-
ComponentFactory,
5-
ComponentFactoryResolver,
64
Injectable,
75
ViewContainerRef
86
} from "@angular/core";
@@ -36,28 +34,10 @@ export class DialogService {
3634
DialogService.dialogRefs.clear();
3735
}
3836

39-
/**
40-
* The default component factory to use when creating dialogs
41-
*/
42-
public componentFactory: ComponentFactory<any>;
43-
4437
/**
4538
* Creates an instance of `DialogService`.
4639
*/
47-
constructor(
48-
protected componentFactoryResolver: ComponentFactoryResolver,
49-
protected injector: Injector,
50-
protected placeholderService: PlaceholderService
51-
) {}
52-
53-
/**
54-
* Set the context for the service. For example, the `component` property can be used to set the
55-
* default component that should be created by the service, for a given instance of the service.
56-
* @param options `{ component: any }` where `component` is a component that extends `dialog.component`
57-
*/
58-
setContext(options: { component: any }) {
59-
this.componentFactory = this.componentFactoryResolver.resolveComponentFactory(options.component);
60-
}
40+
constructor(protected injector: Injector, protected placeholderService: PlaceholderService) {}
6141

6242
/**
6343
* If `dialogRef` is defined, the Dialog is already open. If
@@ -68,25 +48,24 @@ export class DialogService {
6848
* May be `null` if an `cds-placeholder` exists and `dialogConfig.appendInline` is false
6949
* @param dialogConfig the `DialogConfig` for the component
7050
*/
71-
open(viewContainer: ViewContainerRef, dialogConfig: DialogConfig, component?: any) {
72-
let componentFactory = this.componentFactory;
73-
if (component) {
74-
componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
51+
open(viewContainer: ViewContainerRef, dialogConfig: DialogConfig, component: any) {
52+
if (!component) {
53+
return;
7554
}
7655

7756
let dialogRef;
7857
if (dialogConfig.appendInline) {
7958
// add our component to the view
80-
dialogRef = viewContainer.createComponent(componentFactory, 0, this.injector);
59+
dialogRef = viewContainer.createComponent(component, { index: 0, injector: this.injector });
8160
} else if (!this.placeholderService.hasPlaceholderRef()) {
82-
dialogRef = viewContainer.createComponent(componentFactory, 0, this.injector);
61+
dialogRef = viewContainer.createComponent(component, { index: 0, injector: this.injector });
8362
if (dialogRef) {
8463
setTimeout(() => {
8564
window.document.querySelector("body").appendChild(dialogRef.location.nativeElement);
8665
});
8766
}
8867
} else {
89-
dialogRef = this.placeholderService.createComponent(componentFactory, this.injector);
68+
dialogRef = this.placeholderService.createComponent(component, this.injector);
9069
}
9170

9271
// keep track of all initialized dialogs

src/dialog/overflow-menu/overflow-menu-custom-pane.component.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import { closestAttr } from "carbon-components-angular/utils";
66
import { CloseReasons } from "../dialog-config.interface";
77
import { Dialog } from "../dialog.component";
88

9+
/**
10+
* @deprecated as of v5
11+
* Use Toggletip or Popover components instead
12+
*/
913
@Component({
1014
selector: "cds-overflow-custom-menu-pane, ibm-overflow-custom-menu-pane",
1115
template: `

src/dialog/overflow-menu/overflow-menu.directive.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import {
44
ViewContainerRef,
55
Input,
66
TemplateRef,
7-
HostListener,
8-
AfterContentInit
7+
HostListener
98
} from "@angular/core";
109
import { DialogDirective } from "../dialog.directive";
1110
import { DialogService } from "../dialog.service";
@@ -44,7 +43,7 @@ import { EventService } from "carbon-components-angular/utils";
4443
DialogService
4544
]
4645
})
47-
export class OverflowMenuDirective extends DialogDirective implements AfterContentInit {
46+
export class OverflowMenuDirective extends DialogDirective {
4847
/**
4948
* @deprecated as of v5
5049
* Takes a template ref of `OverflowMenuOptions`s
@@ -83,10 +82,6 @@ export class OverflowMenuDirective extends DialogDirective implements AfterConte
8382
super(elementRef, viewContainerRef, dialogService, eventService);
8483
}
8584

86-
ngAfterContentInit() {
87-
this.dialogService.setContext({ component: this.customPane ? OverflowMenuCustomPane : OverflowMenuPane });
88-
}
89-
9085
updateConfig() {
9186
this.dialogConfig.content = this.cdsOverflowMenu;
9287
this.dialogConfig.flip = this.flip;
@@ -103,4 +98,8 @@ export class OverflowMenuDirective extends DialogDirective implements AfterConte
10398
break;
10499
}
105100
}
101+
102+
open() {
103+
return super.open(this.customPane ? OverflowMenuCustomPane : OverflowMenuPane);
104+
}
106105
}

src/modal/base-modal.service.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {
2-
ComponentFactoryResolver,
32
ComponentRef,
43
Injector,
54
Injectable
@@ -20,26 +19,23 @@ export class BaseModalService {
2019
/**
2120
* Creates an instance of `ModalService`.
2221
*/
23-
constructor(public resolver: ComponentFactoryResolver, public placeholderService: PlaceholderService) {}
22+
constructor(public placeholderService: PlaceholderService) {}
2423

2524
/**
2625
* Creates and renders the modal component that is passed in.
2726
* `inputs` is an optional parameter of `data` that can be passed to the `Modal` component.
2827
*/
29-
create<T>(data: {component: any, inputs?: any}): ComponentRef<any> {
30-
let defaults = {inputs: {}};
28+
create<T>(data: { component: any, inputs?: any }): ComponentRef<any> {
29+
let defaults = { inputs: {} };
3130
data = Object.assign({}, defaults, data);
3231

3332
const inputProviders = Object.keys(data.inputs).map(inputName => ({
3433
provide: inputName,
3534
useValue: data.inputs[inputName]
3635
}));
37-
const injector = Injector.create(inputProviders);
38-
const factory = this.resolver.resolveComponentFactory(data.component);
36+
const injector = Injector.create({ providers: inputProviders });
37+
const component = this.placeholderService.createComponent(data.component, injector);
3938
let focusedElement = document.activeElement as HTMLElement;
40-
41-
let component = this.placeholderService.createComponent(factory, injector);
42-
4339
setTimeout(() => {
4440
component.instance.open = true;
4541
});
@@ -84,9 +80,10 @@ export class BaseModalService {
8480

8581
// Let animation finish before component is removed
8682
setTimeout(() => {
87-
this.placeholderService.destroyComponent(BaseModalService.modalList[index]);
88-
BaseModalService.modalList.splice(index, 1);
83+
if (BaseModalService.modalList[index]) {
84+
this.placeholderService.destroyComponent(BaseModalService.modalList[index]);
85+
BaseModalService.modalList.splice(index, 1);
86+
}
8987
}, 240);
9088
}
9189
}
92-

src/modal/modal.service.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { ComponentFactoryResolver } from "@angular/core";
2-
import { Injectable } from "@angular/core";
1+
import { Injectable, ViewContainerRef } from "@angular/core";
32
import { AlertModal } from "./alert-modal.component";
43
import { AlertModalData } from "./alert-modal.interface";
54
import { PlaceholderService } from "carbon-components-angular/placeholder";
@@ -19,11 +18,10 @@ export class ModalService extends BaseModalService {
1918
/**
2019
* Creates an instance of `ModalService`.
2120
*/
22-
constructor(public resolver: ComponentFactoryResolver, public placeholderService: PlaceholderService) {
23-
super(resolver, placeholderService);
21+
constructor(public placeholderService: PlaceholderService) {
22+
super(placeholderService);
2423
}
2524

26-
2725
/**
2826
* Creates and renders a new alert modal component.
2927
* @param data You can pass in:

src/notification/notification.service.ts

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import {
2-
ApplicationRef,
3-
ComponentFactoryResolver,
42
ComponentRef,
53
EventEmitter,
64
Injectable,
7-
Injector,
85
OnDestroy,
9-
NgZone
6+
NgZone,
7+
ViewContainerRef,
8+
Injector
109
} from "@angular/core";
1110

1211
import { NotificationContent, ToastContent, ActionableContent } from "./notification-content.interface";
@@ -30,18 +29,13 @@ export class NotificationService implements OnDestroy {
3029
public onClose: EventEmitter<any> = new EventEmitter();
3130

3231
/**
33-
* Constructs NotificationService.
34-
*
35-
* @param injector
36-
* @param componentFactoryResolver
37-
* @param applicationRef
32+
* Constructs Notification Service
3833
*/
3934
constructor(
4035
protected injector: Injector,
41-
protected componentFactoryResolver: ComponentFactoryResolver,
42-
protected applicationRef: ApplicationRef,
43-
protected ngZone: NgZone) {
44-
}
36+
protected viewContainer: ViewContainerRef,
37+
protected ngZone: NgZone
38+
) {}
4539

4640
/**
4741
* Shows the notification based on the `notificationObj`.
@@ -77,14 +71,11 @@ export class NotificationService implements OnDestroy {
7771
notificationObj: NotificationContent | ToastContent | ActionableContent,
7872
notificationComp = Notification
7973
) {
80-
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(notificationComp);
81-
82-
let notificationRef = componentFactory.create(this.injector);
83-
notificationRef.instance.notificationObj = notificationObj as any; // typescript isn't being very smart here, so we type to any
74+
const notificationRef = this.viewContainer.createComponent(notificationComp);
75+
notificationRef.instance.notificationObj = notificationObj;
8476
this.notificationRefs.push(notificationRef);
8577

8678
this.onClose = notificationRef.instance.close;
87-
this.applicationRef.attachView(notificationRef.hostView);
8879

8980
if (notificationObj.target) {
9081
document.querySelector(notificationObj.target).appendChild(notificationRef.location.nativeElement);
@@ -155,7 +146,6 @@ export class NotificationService implements OnDestroy {
155146
if (notificationRef instanceof Notification) {
156147
this.close(notificationRef.componentRef);
157148
} else {
158-
this.applicationRef.detachView(notificationRef.hostView);
159149
notificationRef.destroy();
160150
const index = this.notificationRefs.indexOf(notificationRef);
161151
if (index !== -1) {
@@ -216,13 +206,8 @@ export class NotificationService implements OnDestroy {
216206
*
217207
*/
218208
ngOnDestroy() {
219-
if (this.notificationRefs.length > 0) {
220-
for (let i = 0; i < this.notificationRefs.length; i++) {
221-
let notificationRef = this.notificationRefs[i];
222-
this.applicationRef.detachView(notificationRef.hostView);
223-
notificationRef.destroy();
224-
}
225-
this.notificationRefs.length = 0;
226-
}
209+
this.notificationRefs.forEach((ref) => {
210+
ref.destroy();
211+
});
227212
}
228213
}

src/placeholder/placeholder.service.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {
22
ComponentRef,
33
ViewContainerRef,
4-
ComponentFactory,
54
Injector
65
} from "@angular/core";
76
import { Injectable } from "@angular/core";
@@ -34,19 +33,19 @@ export class PlaceholderService {
3433
/**
3534
* Creates and returns component in the view.
3635
*/
37-
createComponent(componentFactory: ComponentFactory<any>, injector: Injector, id?: any): ComponentRef<any> {
36+
createComponent(component: ComponentRef<any>, injector: Injector, id?: any): ComponentRef<any> {
3837
if (id) {
3938
if (!this.viewContainerMap.has(id)) {
4039
console.error(`No view container with id ${id} found`);
4140
return;
4241
}
43-
return this.viewContainerMap.get(id).createComponent(componentFactory, this.viewContainerMap.size, injector);
42+
return this.viewContainerMap.get(id).createComponent(component as any, { index: this.viewContainerMap.size, injector });
4443
}
4544
if (!this.viewContainerRef) {
4645
console.error("No view container defined! Likely due to a missing `cds-placeholder`");
4746
return;
4847
}
49-
return this.viewContainerRef.createComponent(componentFactory, this.viewContainerRef.length, injector);
48+
return this.viewContainerRef.createComponent(component as any, { index: this.viewContainerRef.length, injector });
5049
}
5150

5251
destroyComponent(component: ComponentRef<any>) {

0 commit comments

Comments
 (0)