1- import { Component , ComponentFactoryResolver , Inject , Input , OnInit , ViewChild } from '@angular/core' ;
1+ import { Component , ComponentFactoryResolver , Inject , Input , OnInit , ViewChild , OnChanges , SimpleChanges , ComponentRef , ViewContainerRef , ComponentFactory } from '@angular/core' ;
22import {
33 MetadataRepresentation ,
44 MetadataRepresentationType
@@ -8,19 +8,17 @@ import { Context } from '../../core/shared/context.model';
88import { GenericConstructor } from '../../core/shared/generic-constructor' ;
99import { MetadataRepresentationListElementComponent } from '../object-list/metadata-representation-list-element/metadata-representation-list-element.component' ;
1010import { MetadataRepresentationDirective } from './metadata-representation.directive' ;
11- import { hasValue } from '../empty.util' ;
11+ import { hasValue , isNotEmpty , hasNoValue } from '../empty.util' ;
1212import { ThemeService } from '../theme-support/theme.service' ;
1313
1414@Component ( {
1515 selector : 'ds-metadata-representation-loader' ,
16- // styleUrls: ['./metadata-representation-loader.component.scss'],
1716 templateUrl : './metadata-representation-loader.component.html'
1817} )
1918/**
2019 * Component for determining what component to use depending on the item's entity type (dspace.entity.type), its metadata representation and, optionally, its context
2120 */
22- export class MetadataRepresentationLoaderComponent implements OnInit {
23- private componentRefInstance : MetadataRepresentationListElementComponent ;
21+ export class MetadataRepresentationLoaderComponent implements OnInit , OnChanges {
2422
2523 /**
2624 * The item or metadata to determine the component for
@@ -31,8 +29,8 @@ export class MetadataRepresentationLoaderComponent implements OnInit {
3129 }
3230 @Input ( ) set mdRepresentation ( nextValue : MetadataRepresentation ) {
3331 this . _mdRepresentation = nextValue ;
34- if ( hasValue ( this . componentRefInstance ) ) {
35- this . componentRefInstance . metadataRepresentation = nextValue ;
32+ if ( hasValue ( this . compRef ?. instance ) ) {
33+ this . compRef . instance . mdRepresentation = nextValue ;
3634 }
3735 }
3836
@@ -46,6 +44,16 @@ export class MetadataRepresentationLoaderComponent implements OnInit {
4644 */
4745 @ViewChild ( MetadataRepresentationDirective , { static : true } ) mdRepDirective : MetadataRepresentationDirective ;
4846
47+ /**
48+ * The reference to the dynamic component
49+ */
50+ protected compRef : ComponentRef < MetadataRepresentationListElementComponent > ;
51+
52+ protected inAndOutputNames : ( keyof this) [ ] = [
53+ 'context' ,
54+ 'mdRepresentation' ,
55+ ] ;
56+
4957 constructor (
5058 private componentFactoryResolver : ComponentFactoryResolver ,
5159 private themeService : ThemeService ,
@@ -57,14 +65,41 @@ export class MetadataRepresentationLoaderComponent implements OnInit {
5765 * Set up the dynamic child component
5866 */
5967 ngOnInit ( ) : void {
60- const componentFactory = this . componentFactoryResolver . resolveComponentFactory ( this . getComponent ( ) ) ;
68+ this . instantiateComponent ( ) ;
69+ }
70+
71+ /**
72+ * Whenever the inputs change, update the inputs of the dynamic component
73+ */
74+ ngOnChanges ( changes : SimpleChanges ) : void {
75+ if ( hasNoValue ( this . compRef ) ) {
76+ // sometimes the component has not been initialized yet, so it first needs to be initialized
77+ // before being called again
78+ this . instantiateComponent ( changes ) ;
79+ } else {
80+ // if an input or output has changed
81+ if ( this . inAndOutputNames . some ( ( name : any ) => hasValue ( changes [ name ] ) ) ) {
82+ this . connectInputsAndOutputs ( ) ;
83+ if ( this . compRef ?. instance && 'ngOnChanges' in this . compRef . instance ) {
84+ ( this . compRef . instance as any ) . ngOnChanges ( changes ) ;
85+ }
86+ }
87+ }
88+ }
89+
90+ private instantiateComponent ( changes ?: SimpleChanges ) : void {
91+ const componentFactory : ComponentFactory < MetadataRepresentationListElementComponent > = this . componentFactoryResolver . resolveComponentFactory ( this . getComponent ( ) ) ;
6192
62- const viewContainerRef = this . mdRepDirective . viewContainerRef ;
93+ const viewContainerRef : ViewContainerRef = this . mdRepDirective . viewContainerRef ;
6394 viewContainerRef . clear ( ) ;
6495
65- const componentRef = viewContainerRef . createComponent ( componentFactory ) ;
66- this . componentRefInstance = componentRef . instance as MetadataRepresentationListElementComponent ;
67- this . componentRefInstance . metadataRepresentation = this . mdRepresentation ;
96+ this . compRef = viewContainerRef . createComponent ( componentFactory ) ;
97+
98+ if ( hasValue ( changes ) ) {
99+ this . ngOnChanges ( changes ) ;
100+ } else {
101+ this . connectInputsAndOutputs ( ) ;
102+ }
68103 }
69104
70105 /**
@@ -74,4 +109,16 @@ export class MetadataRepresentationLoaderComponent implements OnInit {
74109 private getComponent ( ) : GenericConstructor < MetadataRepresentationListElementComponent > {
75110 return this . getMetadataRepresentationComponent ( this . mdRepresentation . itemType , this . mdRepresentation . representationType , this . context , this . themeService . getThemeName ( ) ) ;
76111 }
112+
113+ /**
114+ * Connect the in and outputs of this component to the dynamic component,
115+ * to ensure they're in sync
116+ */
117+ protected connectInputsAndOutputs ( ) : void {
118+ if ( isNotEmpty ( this . inAndOutputNames ) && hasValue ( this . compRef ) && hasValue ( this . compRef . instance ) ) {
119+ this . inAndOutputNames . filter ( ( name : any ) => this [ name ] !== undefined ) . forEach ( ( name : any ) => {
120+ this . compRef . instance [ name ] = this [ name ] ;
121+ } ) ;
122+ }
123+ }
77124}
0 commit comments