diff --git a/src/app/shared/metadata-representation/metadata-representation-loader.component.html b/src/app/shared/metadata-representation/metadata-representation-loader.component.html
deleted file mode 100644
index 3979c238ad..0000000000
--- a/src/app/shared/metadata-representation/metadata-representation-loader.component.html
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/app/shared/metadata-representation/metadata-representation-loader.component.spec.ts b/src/app/shared/metadata-representation/metadata-representation-loader.component.spec.ts
index 7edf1a700e..c9bec402d1 100644
--- a/src/app/shared/metadata-representation/metadata-representation-loader.component.spec.ts
+++ b/src/app/shared/metadata-representation/metadata-representation-loader.component.spec.ts
@@ -6,10 +6,11 @@ import {
MetadataRepresentationType
} from '../../core/shared/metadata-representation/metadata-representation.model';
import { MetadataRepresentationLoaderComponent } from './metadata-representation-loader.component';
-import { MetadataRepresentationDirective } from './metadata-representation.directive';
+import { DynamicComponentLoaderDirective } from '../abstract-component-loader/dynamic-component-loader.directive';
import { METADATA_REPRESENTATION_COMPONENT_FACTORY } from './metadata-representation.decorator';
import { ThemeService } from '../theme-support/theme.service';
import { PlainTextMetadataListElementComponent } from '../object-list/metadata-representation-list-element/plain-text/plain-text-metadata-list-element.component';
+import { getMockThemeService } from '../mocks/theme-service.mock';
const testType = 'TestType';
const testContext = Context.Search;
@@ -36,12 +37,14 @@ describe('MetadataRepresentationLoaderComponent', () => {
const themeName = 'test-theme';
beforeEach(waitForAsync(() => {
- themeService = jasmine.createSpyObj('themeService', {
- getThemeName: themeName,
- });
+ themeService = getMockThemeService(themeName);
TestBed.configureTestingModule({
imports: [],
- declarations: [MetadataRepresentationLoaderComponent, PlainTextMetadataListElementComponent, MetadataRepresentationDirective],
+ declarations: [
+ MetadataRepresentationLoaderComponent,
+ PlainTextMetadataListElementComponent,
+ DynamicComponentLoaderDirective,
+ ],
schemas: [NO_ERRORS_SCHEMA],
providers: [
{
@@ -64,6 +67,7 @@ describe('MetadataRepresentationLoaderComponent', () => {
beforeEach(waitForAsync(() => {
fixture = TestBed.createComponent(MetadataRepresentationLoaderComponent);
comp = fixture.componentInstance;
+ spyOn(comp, 'getComponent').and.callThrough();
comp.mdRepresentation = new TestType();
comp.context = testContext;
@@ -71,8 +75,8 @@ describe('MetadataRepresentationLoaderComponent', () => {
}));
describe('When the component is rendered', () => {
- it('should call the getMetadataRepresentationComponent function with the right entity type, representation type and context', () => {
- expect((comp as any).getMetadataRepresentationComponent).toHaveBeenCalledWith(testType, testRepresentationType, testContext, themeName);
+ it('should call the getComponent function', () => {
+ expect(comp.getComponent).toHaveBeenCalled();
});
});
});
diff --git a/src/app/shared/metadata-representation/metadata-representation-loader.component.ts b/src/app/shared/metadata-representation/metadata-representation-loader.component.ts
index 42ee093278..83542512ed 100644
--- a/src/app/shared/metadata-representation/metadata-representation-loader.component.ts
+++ b/src/app/shared/metadata-representation/metadata-representation-loader.component.ts
@@ -1,4 +1,4 @@
-import { Component, ComponentFactoryResolver, Inject, Input, OnInit, ViewChild, OnChanges, SimpleChanges, ComponentRef, ViewContainerRef, ComponentFactory } from '@angular/core';
+import { Component, Inject, Input } from '@angular/core';
import {
MetadataRepresentation,
MetadataRepresentationType
@@ -7,118 +7,37 @@ import { METADATA_REPRESENTATION_COMPONENT_FACTORY } from './metadata-representa
import { Context } from '../../core/shared/context.model';
import { GenericConstructor } from '../../core/shared/generic-constructor';
import { MetadataRepresentationListElementComponent } from '../object-list/metadata-representation-list-element/metadata-representation-list-element.component';
-import { MetadataRepresentationDirective } from './metadata-representation.directive';
-import { hasValue, isNotEmpty, hasNoValue } from '../empty.util';
import { ThemeService } from '../theme-support/theme.service';
+import { AbstractComponentLoaderComponent } from '../abstract-component-loader/abstract-component-loader.component';
@Component({
selector: 'ds-metadata-representation-loader',
- templateUrl: './metadata-representation-loader.component.html'
+ templateUrl: '../abstract-component-loader/abstract-component-loader.component.html',
})
/**
* Component for determining what component to use depending on the item's entity type (dspace.entity.type), its metadata representation and, optionally, its context
*/
-export class MetadataRepresentationLoaderComponent implements OnInit, OnChanges {
+export class MetadataRepresentationLoaderComponent extends AbstractComponentLoaderComponent {
/**
* The item or metadata to determine the component for
*/
- private _mdRepresentation: MetadataRepresentation;
- get mdRepresentation(): MetadataRepresentation {
- return this._mdRepresentation;
- }
- @Input() set mdRepresentation(nextValue: MetadataRepresentation) {
- this._mdRepresentation = nextValue;
- if (hasValue(this.compRef?.instance)) {
- this.compRef.instance.mdRepresentation = nextValue;
- }
- }
-
- /**
- * The optional context
- */
- @Input() context: Context;
-
- /**
- * Directive to determine where the dynamic child component is located
- */
- @ViewChild(MetadataRepresentationDirective, {static: true}) mdRepDirective: MetadataRepresentationDirective;
-
- /**
- * The reference to the dynamic component
- */
- protected compRef: ComponentRef;
+ @Input() mdRepresentation: MetadataRepresentation;
protected inAndOutputNames: (keyof this)[] = [
- 'context',
+ ...this.inAndOutputNames,
'mdRepresentation',
];
constructor(
- private componentFactoryResolver: ComponentFactoryResolver,
- private themeService: ThemeService,
+ protected themeService: ThemeService,
@Inject(METADATA_REPRESENTATION_COMPONENT_FACTORY) private getMetadataRepresentationComponent: (entityType: string, mdRepresentationType: MetadataRepresentationType, context: Context, theme: string) => GenericConstructor,
) {
+ super(themeService);
}
- /**
- * Set up the dynamic child component
- */
- ngOnInit(): void {
- this.instantiateComponent();
- }
-
- /**
- * Whenever the inputs change, update the inputs of the dynamic component
- */
- ngOnChanges(changes: SimpleChanges): void {
- if (hasNoValue(this.compRef)) {
- // sometimes the component has not been initialized yet, so it first needs to be initialized
- // before being called again
- this.instantiateComponent(changes);
- } else {
- // if an input or output has changed
- if (this.inAndOutputNames.some((name: any) => hasValue(changes[name]))) {
- this.connectInputsAndOutputs();
- if (this.compRef?.instance && 'ngOnChanges' in this.compRef.instance) {
- (this.compRef.instance as any).ngOnChanges(changes);
- }
- }
- }
- }
-
- private instantiateComponent(changes?: SimpleChanges): void {
- const componentFactory: ComponentFactory = this.componentFactoryResolver.resolveComponentFactory(this.getComponent());
-
- const viewContainerRef: ViewContainerRef = this.mdRepDirective.viewContainerRef;
- viewContainerRef.clear();
-
- this.compRef = viewContainerRef.createComponent(componentFactory);
-
- if (hasValue(changes)) {
- this.ngOnChanges(changes);
- } else {
- this.connectInputsAndOutputs();
- }
- }
-
- /**
- * Fetch the component depending on the item's entity type, metadata representation type and context
- * @returns {string}
- */
- private getComponent(): GenericConstructor {
+ public getComponent(): GenericConstructor {
return this.getMetadataRepresentationComponent(this.mdRepresentation.itemType, this.mdRepresentation.representationType, this.context, this.themeService.getThemeName());
}
- /**
- * Connect the in and outputs of this component to the dynamic component,
- * to ensure they're in sync
- */
- protected connectInputsAndOutputs(): void {
- if (isNotEmpty(this.inAndOutputNames) && hasValue(this.compRef) && hasValue(this.compRef.instance)) {
- this.inAndOutputNames.filter((name: any) => this[name] !== undefined).forEach((name: any) => {
- this.compRef.instance[name] = this[name];
- });
- }
- }
}
diff --git a/src/app/shared/metadata-representation/metadata-representation.directive.ts b/src/app/shared/metadata-representation/metadata-representation.directive.ts
deleted file mode 100644
index 9ff0573baf..0000000000
--- a/src/app/shared/metadata-representation/metadata-representation.directive.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { Directive, ViewContainerRef } from '@angular/core';
-
-@Directive({
- selector: '[dsMetadataRepresentation]',
-})
-/**
- * Directive used as a hook to know where to inject the dynamic metadata representation component
- */
-export class MetadataRepresentationDirective {
- constructor(public viewContainerRef: ViewContainerRef) { }
-}
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index c00b09e20f..bce7282e8b 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -170,7 +170,6 @@ import { AccessStatusBadgeComponent } from './object-collection/shared/badges/ac
import {
MetadataRepresentationLoaderComponent
} from './metadata-representation/metadata-representation-loader.component';
-import { MetadataRepresentationDirective } from './metadata-representation/metadata-representation.directive';
import {
ListableObjectComponentLoaderComponent
} from './object-collection/shared/listable-object/listable-object-component-loader.component';
@@ -481,7 +480,6 @@ const DIRECTIVES = [
InListValidator,
AutoFocusDirective,
RoleDirective,
- MetadataRepresentationDirective,
FileValueAccessorDirective,
FileValidator,
NgForTrackByIdDirective,