mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
Make MetadataRepresentationLoaderComponent extend AbstractComponentLoaderComponent
This commit is contained in:
@@ -1 +0,0 @@
|
|||||||
<ng-container dsMetadataRepresentation></ng-container>
|
|
@@ -6,10 +6,11 @@ import {
|
|||||||
MetadataRepresentationType
|
MetadataRepresentationType
|
||||||
} from '../../core/shared/metadata-representation/metadata-representation.model';
|
} from '../../core/shared/metadata-representation/metadata-representation.model';
|
||||||
import { MetadataRepresentationLoaderComponent } from './metadata-representation-loader.component';
|
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 { METADATA_REPRESENTATION_COMPONENT_FACTORY } from './metadata-representation.decorator';
|
||||||
import { ThemeService } from '../theme-support/theme.service';
|
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 { 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 testType = 'TestType';
|
||||||
const testContext = Context.Search;
|
const testContext = Context.Search;
|
||||||
@@ -36,12 +37,14 @@ describe('MetadataRepresentationLoaderComponent', () => {
|
|||||||
const themeName = 'test-theme';
|
const themeName = 'test-theme';
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(waitForAsync(() => {
|
||||||
themeService = jasmine.createSpyObj('themeService', {
|
themeService = getMockThemeService(themeName);
|
||||||
getThemeName: themeName,
|
|
||||||
});
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [],
|
imports: [],
|
||||||
declarations: [MetadataRepresentationLoaderComponent, PlainTextMetadataListElementComponent, MetadataRepresentationDirective],
|
declarations: [
|
||||||
|
MetadataRepresentationLoaderComponent,
|
||||||
|
PlainTextMetadataListElementComponent,
|
||||||
|
DynamicComponentLoaderDirective,
|
||||||
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA],
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
@@ -64,6 +67,7 @@ describe('MetadataRepresentationLoaderComponent', () => {
|
|||||||
beforeEach(waitForAsync(() => {
|
beforeEach(waitForAsync(() => {
|
||||||
fixture = TestBed.createComponent(MetadataRepresentationLoaderComponent);
|
fixture = TestBed.createComponent(MetadataRepresentationLoaderComponent);
|
||||||
comp = fixture.componentInstance;
|
comp = fixture.componentInstance;
|
||||||
|
spyOn(comp, 'getComponent').and.callThrough();
|
||||||
|
|
||||||
comp.mdRepresentation = new TestType();
|
comp.mdRepresentation = new TestType();
|
||||||
comp.context = testContext;
|
comp.context = testContext;
|
||||||
@@ -71,8 +75,8 @@ describe('MetadataRepresentationLoaderComponent', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
describe('When the component is rendered', () => {
|
describe('When the component is rendered', () => {
|
||||||
it('should call the getMetadataRepresentationComponent function with the right entity type, representation type and context', () => {
|
it('should call the getComponent function', () => {
|
||||||
expect((comp as any).getMetadataRepresentationComponent).toHaveBeenCalledWith(testType, testRepresentationType, testContext, themeName);
|
expect(comp.getComponent).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -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 {
|
import {
|
||||||
MetadataRepresentation,
|
MetadataRepresentation,
|
||||||
MetadataRepresentationType
|
MetadataRepresentationType
|
||||||
@@ -7,118 +7,37 @@ import { METADATA_REPRESENTATION_COMPONENT_FACTORY } from './metadata-representa
|
|||||||
import { Context } from '../../core/shared/context.model';
|
import { Context } from '../../core/shared/context.model';
|
||||||
import { GenericConstructor } from '../../core/shared/generic-constructor';
|
import { GenericConstructor } from '../../core/shared/generic-constructor';
|
||||||
import { MetadataRepresentationListElementComponent } from '../object-list/metadata-representation-list-element/metadata-representation-list-element.component';
|
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 { ThemeService } from '../theme-support/theme.service';
|
||||||
|
import { AbstractComponentLoaderComponent } from '../abstract-component-loader/abstract-component-loader.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-metadata-representation-loader',
|
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
|
* 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
|
* The item or metadata to determine the component for
|
||||||
*/
|
*/
|
||||||
private _mdRepresentation: MetadataRepresentation;
|
@Input() 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<MetadataRepresentationListElementComponent>;
|
|
||||||
|
|
||||||
protected inAndOutputNames: (keyof this)[] = [
|
protected inAndOutputNames: (keyof this)[] = [
|
||||||
'context',
|
...this.inAndOutputNames,
|
||||||
'mdRepresentation',
|
'mdRepresentation',
|
||||||
];
|
];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private componentFactoryResolver: ComponentFactoryResolver,
|
protected themeService: ThemeService,
|
||||||
private themeService: ThemeService,
|
|
||||||
@Inject(METADATA_REPRESENTATION_COMPONENT_FACTORY) private getMetadataRepresentationComponent: (entityType: string, mdRepresentationType: MetadataRepresentationType, context: Context, theme: string) => GenericConstructor<any>,
|
@Inject(METADATA_REPRESENTATION_COMPONENT_FACTORY) private getMetadataRepresentationComponent: (entityType: string, mdRepresentationType: MetadataRepresentationType, context: Context, theme: string) => GenericConstructor<any>,
|
||||||
) {
|
) {
|
||||||
|
super(themeService);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public getComponent(): GenericConstructor<MetadataRepresentationListElementComponent> {
|
||||||
* 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> {
|
|
||||||
return this.getMetadataRepresentationComponent(this.mdRepresentation.itemType, this.mdRepresentation.representationType, this.context, this.themeService.getThemeName());
|
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];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -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) { }
|
|
||||||
}
|
|
@@ -170,7 +170,6 @@ import { AccessStatusBadgeComponent } from './object-collection/shared/badges/ac
|
|||||||
import {
|
import {
|
||||||
MetadataRepresentationLoaderComponent
|
MetadataRepresentationLoaderComponent
|
||||||
} from './metadata-representation/metadata-representation-loader.component';
|
} from './metadata-representation/metadata-representation-loader.component';
|
||||||
import { MetadataRepresentationDirective } from './metadata-representation/metadata-representation.directive';
|
|
||||||
import {
|
import {
|
||||||
ListableObjectComponentLoaderComponent
|
ListableObjectComponentLoaderComponent
|
||||||
} from './object-collection/shared/listable-object/listable-object-component-loader.component';
|
} from './object-collection/shared/listable-object/listable-object-component-loader.component';
|
||||||
@@ -481,7 +480,6 @@ const DIRECTIVES = [
|
|||||||
InListValidator,
|
InListValidator,
|
||||||
AutoFocusDirective,
|
AutoFocusDirective,
|
||||||
RoleDirective,
|
RoleDirective,
|
||||||
MetadataRepresentationDirective,
|
|
||||||
FileValueAccessorDirective,
|
FileValueAccessorDirective,
|
||||||
FileValidator,
|
FileValidator,
|
||||||
NgForTrackByIdDirective,
|
NgForTrackByIdDirective,
|
||||||
|
Reference in New Issue
Block a user