Skip to content

Commit

Permalink
Make MetadataRepresentationLoaderComponent extend AbstractComponentLo…
Browse files Browse the repository at this point in the history
…aderComponent
  • Loading branch information
alexandrevryghem committed Jun 23, 2023
1 parent 0a7fb76 commit d59c5c4
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 96 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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: [
{
Expand All @@ -64,15 +67,16 @@ describe('MetadataRepresentationLoaderComponent', () => {
beforeEach(waitForAsync(() => {
fixture = TestBed.createComponent(MetadataRepresentationLoaderComponent);
comp = fixture.componentInstance;
spyOn(comp, 'getComponent').and.callThrough();

comp.mdRepresentation = new TestType();
comp.context = testContext;
fixture.detectChanges();
}));

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();
});
});
});
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<MetadataRepresentationListElementComponent> {

/**
* 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)) {
Expand All @@ -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<MetadataRepresentationListElementComponent>;

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<any>,
) {
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<MetadataRepresentationListElementComponent> = 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<MetadataRepresentationListElementComponent> {
public getComponent(): GenericConstructor<MetadataRepresentationListElementComponent> {
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];
});
}
}
}

This file was deleted.

2 changes: 0 additions & 2 deletions src/app/shared/shared.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -481,7 +480,6 @@ const DIRECTIVES = [
InListValidator,
AutoFocusDirective,
RoleDirective,
MetadataRepresentationDirective,
FileValueAccessorDirective,
FileValidator,
NgForTrackByIdDirective,
Expand Down

0 comments on commit d59c5c4

Please sign in to comment.