From d59c5c4fd8b8d8cc5ab8b3bfcdef0c6bbf9713e1 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Sat, 10 Jun 2023 16:14:54 +0200 Subject: [PATCH] Make MetadataRepresentationLoaderComponent extend AbstractComponentLoaderComponent --- ...adata-representation-loader.component.html | 1 - ...ta-representation-loader.component.spec.ts | 18 ++-- ...etadata-representation-loader.component.ts | 86 +++---------------- .../metadata-representation.directive.ts | 11 --- src/app/shared/shared.module.ts | 2 - 5 files changed, 22 insertions(+), 96 deletions(-) delete mode 100644 src/app/shared/metadata-representation/metadata-representation-loader.component.html delete mode 100644 src/app/shared/metadata-representation/metadata-representation.directive.ts 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 3979c238adf..00000000000 --- 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 7edf1a700e5..c9bec402d16 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 42ee093278a..10802c63580 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,26 +7,28 @@ 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 { hasValue } 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)) { @@ -39,86 +41,20 @@ export class MetadataRepresentationLoaderComponent implements OnInit, OnChanges */ @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; - protected inAndOutputNames: (keyof this)[] = [ - 'context', 'mdRepresentation', + 'context', ]; 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 9ff0573baff..00000000000 --- 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 c00b09e20fc..bce7282e8b5 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,