Skip to content

Commit 4602cdd

Browse files
Merge branch 'memory-leak-fixes_contribute-7.6' into generify-component-loaders_contribute-main
2 parents 82d4ccf + 6497a15 commit 4602cdd

7 files changed

Lines changed: 101 additions & 68 deletions

File tree

src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.ts

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, ComponentFactoryResolver, ElementRef, OnInit, ViewChild } from '@angular/core';
1+
import { Component, ComponentRef, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
22
import { Item } from '../../../../../core/shared/item.model';
33
import { ViewMode } from '../../../../../core/shared/view-mode.model';
44
import {
@@ -14,6 +14,7 @@ import { GenericConstructor } from '../../../../../core/shared/generic-construct
1414
import { DynamicComponentLoaderDirective } from '../../../../../shared/abstract-component-loader/dynamic-component-loader.directive';
1515
import { ThemeService } from '../../../../../shared/theme-support/theme.service';
1616
import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service';
17+
import { hasValue } from '../../../../../shared/empty.util';
1718

1819
@listableObjectComponent(ItemSearchResult, ViewMode.GridElement, Context.AdminSearch)
1920
@Component({
@@ -24,17 +25,18 @@ import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service
2425
/**
2526
* The component for displaying a list element for an item search result on the admin search page
2627
*/
27-
export class ItemAdminSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> implements OnInit {
28+
export class ItemAdminSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> implements OnDestroy, OnInit {
2829
@ViewChild(DynamicComponentLoaderDirective, { static: true }) dynamicComponentLoaderDirective: DynamicComponentLoaderDirective;
2930
@ViewChild('badges', { static: true }) badges: ElementRef;
3031
@ViewChild('buttons', { static: true }) buttons: ElementRef;
3132

33+
protected compRef: ComponentRef<Component>;
34+
3235
constructor(
3336
public dsoNameService: DSONameService,
3437
protected truncatableService: TruncatableService,
3538
protected bitstreamDataService: BitstreamDataService,
3639
private themeService: ThemeService,
37-
private componentFactoryResolver: ComponentFactoryResolver,
3840
) {
3941
super(dsoNameService, truncatableService, bitstreamDataService);
4042
}
@@ -44,23 +46,32 @@ export class ItemAdminSearchResultGridElementComponent extends SearchResultGridE
4446
*/
4547
ngOnInit(): void {
4648
super.ngOnInit();
47-
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.getComponent());
49+
const component: GenericConstructor<Component> = this.getComponent();
4850

4951
const viewContainerRef = this.dynamicComponentLoaderDirective.viewContainerRef;
5052
viewContainerRef.clear();
5153

52-
const componentRef = viewContainerRef.createComponent(
53-
componentFactory,
54-
0,
55-
undefined,
56-
[
57-
[this.badges.nativeElement],
58-
[this.buttons.nativeElement]
59-
]);
60-
(componentRef.instance as any).object = this.object;
61-
(componentRef.instance as any).index = this.index;
62-
(componentRef.instance as any).linkType = this.linkType;
63-
(componentRef.instance as any).listID = this.listID;
54+
this.compRef = viewContainerRef.createComponent(
55+
component, {
56+
index: 0,
57+
injector: undefined,
58+
projectableNodes: [
59+
[this.badges.nativeElement],
60+
[this.buttons.nativeElement],
61+
],
62+
},
63+
);
64+
this.compRef.setInput('object',this.object);
65+
this.compRef.setInput('index', this.index);
66+
this.compRef.setInput('linkType', this.linkType);
67+
this.compRef.setInput('listID', this.listID);
68+
}
69+
70+
ngOnDestroy(): void {
71+
if (hasValue(this.compRef)) {
72+
this.compRef.destroy();
73+
this.compRef = undefined;
74+
}
6475
}
6576

6677
/**

src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/workflow-item/workflow-item-search-result-admin-workflow-grid-element.component.ts

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, ComponentFactoryResolver, ElementRef, ViewChild } from '@angular/core';
1+
import { Component, ElementRef, ViewChild, ComponentRef, OnDestroy, OnInit } from '@angular/core';
22
import { Item } from '../../../../../core/shared/item.model';
33
import { ViewMode } from '../../../../../core/shared/view-mode.model';
44
import {
@@ -24,6 +24,7 @@ import { take } from 'rxjs/operators';
2424
import { WorkflowItemSearchResult } from '../../../../../shared/object-collection/shared/workflow-item-search-result.model';
2525
import { ThemeService } from '../../../../../shared/theme-support/theme.service';
2626
import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service';
27+
import { hasValue } from '../../../../../shared/empty.util';
2728

2829
@listableObjectComponent(WorkflowItemSearchResult, ViewMode.GridElement, Context.AdminWorkflowSearch)
2930
@Component({
@@ -34,7 +35,7 @@ import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service
3435
/**
3536
* The component for displaying a grid element for an workflow item on the admin workflow search page
3637
*/
37-
export class WorkflowItemSearchResultAdminWorkflowGridElementComponent extends SearchResultGridElementComponent<WorkflowItemSearchResult, WorkflowItem> {
38+
export class WorkflowItemSearchResultAdminWorkflowGridElementComponent extends SearchResultGridElementComponent<WorkflowItemSearchResult, WorkflowItem> implements OnDestroy, OnInit {
3839
/**
3940
* Directive used to render the dynamic component in
4041
*/
@@ -55,9 +56,10 @@ export class WorkflowItemSearchResultAdminWorkflowGridElementComponent extends S
5556
*/
5657
public item$: Observable<Item>;
5758

59+
protected compRef: ComponentRef<Component>;
60+
5861
constructor(
5962
public dsoNameService: DSONameService,
60-
private componentFactoryResolver: ComponentFactoryResolver,
6163
private linkService: LinkService,
6264
protected truncatableService: TruncatableService,
6365
private themeService: ThemeService,
@@ -75,26 +77,34 @@ export class WorkflowItemSearchResultAdminWorkflowGridElementComponent extends S
7577
this.dso = this.linkService.resolveLink(this.dso, followLink('item'));
7678
this.item$ = (this.dso.item as Observable<RemoteData<Item>>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload());
7779
this.item$.pipe(take(1)).subscribe((item: Item) => {
78-
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.getComponent(item));
80+
const component: GenericConstructor<Component> = this.getComponent(item);
7981

80-
const viewContainerRef = this.dynamicComponentLoaderDirective.viewContainerRef;
81-
viewContainerRef.clear();
82+
const viewContainerRef = this.dynamicComponentLoaderDirective.viewContainerRef;
83+
viewContainerRef.clear();
8284

83-
const componentRef = viewContainerRef.createComponent(
84-
componentFactory,
85-
0,
86-
undefined,
87-
[
85+
this.compRef = viewContainerRef.createComponent(
86+
component, {
87+
index: 0,
88+
injector: undefined,
89+
projectableNodes: [
8890
[this.badges.nativeElement],
89-
[this.buttons.nativeElement]
90-
]);
91-
(componentRef.instance as any).object = item;
92-
(componentRef.instance as any).index = this.index;
93-
(componentRef.instance as any).linkType = this.linkType;
94-
(componentRef.instance as any).listID = this.listID;
95-
componentRef.changeDetectorRef.detectChanges();
96-
}
97-
);
91+
[this.buttons.nativeElement],
92+
],
93+
},
94+
);
95+
this.compRef.setInput('object', item);
96+
this.compRef.setInput('index', this.index);
97+
this.compRef.setInput('linkType', this.linkType);
98+
this.compRef.setInput('listID', this.listID);
99+
this.compRef.changeDetectorRef.detectChanges();
100+
});
101+
}
102+
103+
ngOnDestroy(): void {
104+
if (hasValue(this.compRef)) {
105+
this.compRef.destroy();
106+
this.compRef = undefined;
107+
}
98108
}
99109

100110
/**

src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/workspace-item/workspace-item-search-result-admin-workflow-grid-element.component.ts

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, ComponentFactoryResolver, ElementRef, ViewChild, OnInit } from '@angular/core';
1+
import { Component, ElementRef, ViewChild, OnInit, OnDestroy, ComponentRef } from '@angular/core';
22

33
import { BehaviorSubject, Observable } from 'rxjs';
44
import { map, mergeMap, take, tap } from 'rxjs/operators';
@@ -35,6 +35,7 @@ import { SupervisionOrder } from '../../../../../core/supervision-order/models/s
3535
import { PaginatedList } from '../../../../../core/data/paginated-list.model';
3636
import { SupervisionOrderDataService } from '../../../../../core/supervision-order/supervision-order-data.service';
3737
import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service';
38+
import { hasValue } from '../../../../../shared/empty.util';
3839

3940
@listableObjectComponent(WorkspaceItemSearchResult, ViewMode.GridElement, Context.AdminWorkflowSearch)
4041
@Component({
@@ -45,7 +46,7 @@ import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service
4546
/**
4647
* The component for displaying a grid element for an workflow item on the admin workflow search page
4748
*/
48-
export class WorkspaceItemSearchResultAdminWorkflowGridElementComponent extends SearchResultGridElementComponent<WorkspaceItemSearchResult, WorkspaceItem> implements OnInit {
49+
export class WorkspaceItemSearchResultAdminWorkflowGridElementComponent extends SearchResultGridElementComponent<WorkspaceItemSearchResult, WorkspaceItem> implements OnDestroy, OnInit {
4950

5051
/**
5152
* The item linked to the workspace item
@@ -77,9 +78,13 @@ export class WorkspaceItemSearchResultAdminWorkflowGridElementComponent extends
7778
*/
7879
@ViewChild('buttons', { static: true }) buttons: ElementRef;
7980

81+
/**
82+
* The reference to the dynamic component
83+
*/
84+
protected compRef: ComponentRef<Component>;
85+
8086
constructor(
8187
public dsoNameService: DSONameService,
82-
private componentFactoryResolver: ComponentFactoryResolver,
8388
private linkService: LinkService,
8489
protected truncatableService: TruncatableService,
8590
private themeService: ThemeService,
@@ -98,24 +103,24 @@ export class WorkspaceItemSearchResultAdminWorkflowGridElementComponent extends
98103
this.dso = this.linkService.resolveLink(this.dso, followLink('item'));
99104
this.item$ = (this.dso.item as Observable<RemoteData<Item>>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload());
100105
this.item$.pipe(take(1)).subscribe((item: Item) => {
101-
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.getComponent(item));
106+
const component: GenericConstructor<Component> = this.getComponent(item);
102107

103108
const viewContainerRef = this.dynamicComponentLoaderDirective.viewContainerRef;
104109
viewContainerRef.clear();
105110

106-
const componentRef = viewContainerRef.createComponent(
107-
componentFactory,
108-
0,
109-
undefined,
110-
[
111+
this.compRef = viewContainerRef.createComponent(
112+
component, {
113+
index: 0,
114+
projectableNodes: [
111115
[this.badges.nativeElement],
112116
[this.buttons.nativeElement]
113-
]);
114-
(componentRef.instance as any).object = item;
115-
(componentRef.instance as any).index = this.index;
116-
(componentRef.instance as any).linkType = this.linkType;
117-
(componentRef.instance as any).listID = this.listID;
118-
componentRef.changeDetectorRef.detectChanges();
117+
],
118+
});
119+
this.compRef.setInput('object', item);
120+
this.compRef.setInput('index', this.index);
121+
this.compRef.setInput('linkType', this.linkType);
122+
this.compRef.setInput('listID', this.listID);
123+
this.compRef.changeDetectorRef.detectChanges();
119124
}
120125
);
121126

@@ -128,6 +133,13 @@ export class WorkspaceItemSearchResultAdminWorkflowGridElementComponent extends
128133
});
129134
}
130135

136+
ngOnDestroy(): void {
137+
if (hasValue(this.compRef)) {
138+
this.compRef.destroy();
139+
this.compRef = undefined;
140+
}
141+
}
142+
131143
/**
132144
* Fetch the component depending on the item's entity type, view mode and context
133145
* @returns {GenericConstructor<Component>}

src/app/shared/abstract-component-loader/abstract-component-loader.component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export abstract class AbstractComponentLoaderComponent<T> implements OnInit, OnC
8585
this.subs
8686
.filter((subscription: Subscription) => hasValue(subscription))
8787
.forEach((subscription: Subscription) => subscription.unsubscribe());
88+
this.destroyComponentInstance();
8889
}
8990

9091
/**

src/app/shared/context-help.directive.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {
2-
ComponentFactoryResolver,
32
ComponentRef,
43
Directive,
54
Input,
@@ -12,6 +11,7 @@ import { PlacementArray } from '@ng-bootstrap/ng-bootstrap/util/positioning';
1211
import { ContextHelpWrapperComponent } from './context-help-wrapper/context-help-wrapper.component';
1312
import { PlacementDir } from './context-help-wrapper/placement-dir.model';
1413
import { ContextHelpService } from './context-help.service';
14+
import { hasValue } from './empty.util';
1515

1616
export interface ContextHelpDirectiveInput {
1717
content: string;
@@ -43,7 +43,6 @@ export class ContextHelpDirective implements OnChanges, OnDestroy {
4343
constructor(
4444
private templateRef: TemplateRef<any>,
4545
private viewContainerRef: ViewContainerRef,
46-
private componentFactoryResolver: ComponentFactoryResolver,
4746
private contextHelpService: ContextHelpService
4847
) {}
4948

@@ -53,19 +52,21 @@ export class ContextHelpDirective implements OnChanges, OnDestroy {
5352
this.contextHelpService.add({id: this.dsContextHelp.id, isTooltipVisible: false});
5453

5554
if (this.wrapper === undefined) {
56-
const factory
57-
= this.componentFactoryResolver.resolveComponentFactory(ContextHelpWrapperComponent);
58-
this.wrapper = this.viewContainerRef.createComponent(factory);
55+
this.wrapper = this.viewContainerRef.createComponent(ContextHelpWrapperComponent);
5956
}
60-
this.wrapper.instance.templateRef = this.templateRef;
61-
this.wrapper.instance.content = this.dsContextHelp.content;
62-
this.wrapper.instance.id = this.dsContextHelp.id;
63-
this.wrapper.instance.tooltipPlacement = this.dsContextHelp.tooltipPlacement;
64-
this.wrapper.instance.iconPlacement = this.dsContextHelp.iconPlacement;
57+
this.wrapper.setInput('templateRef', this.templateRef);
58+
this.wrapper.setInput('content', this.dsContextHelp.content);
59+
this.wrapper.setInput('id', this.dsContextHelp.id);
60+
this.wrapper.setInput('tooltipPlacement', this.dsContextHelp.tooltipPlacement);
61+
this.wrapper.setInput('iconPlacement', this.dsContextHelp.iconPlacement);
6562
}
6663

6764
ngOnDestroy() {
6865
this.clearMostRecentId();
66+
if (hasValue(this.wrapper)) {
67+
this.wrapper.destroy();
68+
this.wrapper = undefined;
69+
}
6970
}
7071

7172
private clearMostRecentId(): void {

src/app/shared/loading/themed-loading.component.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, Input, ComponentFactoryResolver, ChangeDetectorRef } from '@angular/core';
1+
import { Component, Input, ChangeDetectorRef } from '@angular/core';
22
import { ThemedComponent } from '../theme-support/themed.component';
33
import { LoadingComponent } from './loading.component';
44
import { ThemeService } from '../theme-support/theme.service';
@@ -20,11 +20,10 @@ export class ThemedLoadingComponent extends ThemedComponent<LoadingComponent> {
2020
protected inAndOutputNames: (keyof LoadingComponent & keyof this)[] = ['message', 'showMessage', 'spinner'];
2121

2222
constructor(
23-
protected resolver: ComponentFactoryResolver,
2423
protected cdr: ChangeDetectorRef,
2524
protected themeService: ThemeService
2625
) {
27-
super(resolver, cdr, themeService);
26+
super(cdr, themeService);
2827
}
2928

3029
protected getComponentName(): string {

src/app/shared/theme-support/themed.component.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
ComponentRef,
77
SimpleChanges,
88
OnDestroy,
9-
ComponentFactoryResolver,
109
ChangeDetectorRef,
1110
OnChanges,
1211
HostBinding,
@@ -47,7 +46,6 @@ export abstract class ThemedComponent<T> implements AfterViewInit, OnDestroy, On
4746
@HostBinding('attr.data-used-theme') usedTheme: string;
4847

4948
constructor(
50-
protected resolver: ComponentFactoryResolver,
5149
protected cdr: ChangeDetectorRef,
5250
protected themeService: ThemeService,
5351
) {
@@ -118,8 +116,9 @@ export abstract class ThemedComponent<T> implements AfterViewInit, OnDestroy, On
118116

119117
this.lazyLoadSub = this.lazyLoadObs.subscribe(([simpleChanges, constructor]: [SimpleChanges, GenericConstructor<T>]) => {
120118
this.destroyComponentInstance();
121-
const factory = this.resolver.resolveComponentFactory(constructor);
122-
this.compRef = this.vcr.createComponent(factory, undefined, undefined, [this.themedElementContent.nativeElement.childNodes]);
119+
this.compRef = this.vcr.createComponent(constructor, {
120+
projectableNodes: [this.themedElementContent.nativeElement.childNodes],
121+
});
123122
if (hasValue(simpleChanges)) {
124123
this.ngOnChanges(simpleChanges);
125124
} else {

0 commit comments

Comments
 (0)