mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-13 13:03:04 +00:00
Fixed getComponent not triggering again when it's input values change by creating inputNamesDependentForComponent
Also simplified the way @Input() values are passed to their child component and how ngOnChanges is called by using setInput instead
This commit is contained in:
@@ -32,10 +32,22 @@ export abstract class AbstractComponentLoaderComponent<T> implements OnInit, OnC
|
|||||||
*/
|
*/
|
||||||
protected subs: Subscription[] = [];
|
protected subs: Subscription[] = [];
|
||||||
|
|
||||||
protected inAndOutputNames: (keyof this)[] = [
|
/**
|
||||||
|
* The @{@link Input}() that are used to find the matching component using {@link getComponent}. When the value of
|
||||||
|
* one of these @{@link Input}() change this loader needs to retrieve the best matching component again using the
|
||||||
|
* {@link getComponent} method.
|
||||||
|
*/
|
||||||
|
protected inputNamesDependentForComponent: (keyof this & string)[] = [
|
||||||
'context',
|
'context',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected inputNames: (keyof this & string)[] = [
|
||||||
|
'context',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected outputNames: (keyof this & string)[] = [
|
||||||
|
];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected themeService: ThemeService,
|
protected themeService: ThemeService,
|
||||||
) {
|
) {
|
||||||
@@ -45,7 +57,9 @@ export abstract class AbstractComponentLoaderComponent<T> implements OnInit, OnC
|
|||||||
* Set up the dynamic child component
|
* Set up the dynamic child component
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.instantiateComponent();
|
if (hasNoValue(this.compRef)) {
|
||||||
|
this.instantiateComponent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,14 +69,14 @@ export abstract class AbstractComponentLoaderComponent<T> implements OnInit, OnC
|
|||||||
if (hasNoValue(this.compRef)) {
|
if (hasNoValue(this.compRef)) {
|
||||||
// sometimes the component has not been initialized yet, so it first needs to be initialized
|
// sometimes the component has not been initialized yet, so it first needs to be initialized
|
||||||
// before being called again
|
// before being called again
|
||||||
this.instantiateComponent(changes);
|
this.instantiateComponent();
|
||||||
} else {
|
} else {
|
||||||
// if an input or output has changed
|
if (this.inputNamesDependentForComponent.some((name: any) => hasValue(changes[name]) && changes[name].previousValue !== changes[name].currentValue)) {
|
||||||
if (this.inAndOutputNames.some((name: any) => hasValue(changes[name]))) {
|
// Recreate the component when the @Input()s used by getComponent() aren't up-to-date anymore
|
||||||
|
this.destroyComponentInstance();
|
||||||
|
this.instantiateComponent();
|
||||||
|
} else {
|
||||||
this.connectInputsAndOutputs();
|
this.connectInputsAndOutputs();
|
||||||
if (this.compRef?.instance && 'ngOnChanges' in this.compRef.instance) {
|
|
||||||
(this.compRef.instance as any).ngOnChanges(changes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +87,10 @@ export abstract class AbstractComponentLoaderComponent<T> implements OnInit, OnC
|
|||||||
.forEach((subscription: Subscription) => subscription.unsubscribe());
|
.forEach((subscription: Subscription) => subscription.unsubscribe());
|
||||||
}
|
}
|
||||||
|
|
||||||
public instantiateComponent(changes?: SimpleChanges): void {
|
/**
|
||||||
|
* Creates the component and connects the @Input() & @Output() from the ThemedComponent to its child Component.
|
||||||
|
*/
|
||||||
|
public instantiateComponent(): void {
|
||||||
const component: GenericConstructor<T> = this.getComponent();
|
const component: GenericConstructor<T> = this.getComponent();
|
||||||
|
|
||||||
const viewContainerRef: ViewContainerRef = this.componentDirective.viewContainerRef;
|
const viewContainerRef: ViewContainerRef = this.componentDirective.viewContainerRef;
|
||||||
@@ -86,10 +103,16 @@ export abstract class AbstractComponentLoaderComponent<T> implements OnInit, OnC
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (hasValue(changes)) {
|
this.connectInputsAndOutputs();
|
||||||
this.ngOnChanges(changes);
|
}
|
||||||
} else {
|
|
||||||
this.connectInputsAndOutputs();
|
/**
|
||||||
|
* Destroys the themed component and calls it's `ngOnDestroy`
|
||||||
|
*/
|
||||||
|
public destroyComponentInstance(): void {
|
||||||
|
if (hasValue(this.compRef)) {
|
||||||
|
this.compRef.destroy();
|
||||||
|
this.compRef = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,12 +122,18 @@ export abstract class AbstractComponentLoaderComponent<T> implements OnInit, OnC
|
|||||||
public abstract getComponent(): GenericConstructor<T>;
|
public abstract getComponent(): GenericConstructor<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect the in and outputs of this component to the dynamic component,
|
* Connect the inputs and outputs of this component to the dynamic component,
|
||||||
* to ensure they're in sync
|
* to ensure they're in sync
|
||||||
*/
|
*/
|
||||||
protected connectInputsAndOutputs(): void {
|
protected connectInputsAndOutputs(): void {
|
||||||
if (isNotEmpty(this.inAndOutputNames) && hasValue(this.compRef) && hasValue(this.compRef.instance)) {
|
if (isNotEmpty(this.inputNames) && hasValue(this.compRef) && hasValue(this.compRef.instance)) {
|
||||||
this.inAndOutputNames.filter((name: any) => this[name] !== undefined).forEach((name: any) => {
|
this.inputNames.filter((name: string) => this[name] !== undefined).filter((name: string) => this[name] !== this.compRef.instance[name]).forEach((name: string) => {
|
||||||
|
// Using setInput will automatically trigger the ngOnChanges
|
||||||
|
this.compRef.setInput(name, this[name]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (isNotEmpty(this.outputNames) && hasValue(this.compRef) && hasValue(this.compRef.instance)) {
|
||||||
|
this.outputNames.filter((name: string) => this[name] !== undefined).filter((name: string) => this[name] !== this.compRef.instance[name]).forEach((name: string) => {
|
||||||
this.compRef.instance[name] = this[name];
|
this.compRef.instance[name] = this[name];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -24,8 +24,8 @@ export class MetadataRepresentationLoaderComponent extends AbstractComponentLoad
|
|||||||
*/
|
*/
|
||||||
@Input() mdRepresentation: MetadataRepresentation;
|
@Input() mdRepresentation: MetadataRepresentation;
|
||||||
|
|
||||||
protected inAndOutputNames: (keyof this)[] = [
|
protected inputNames: (keyof this & string)[] = [
|
||||||
...this.inAndOutputNames,
|
...this.inputNames,
|
||||||
'mdRepresentation',
|
'mdRepresentation',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, } from '@angular/core';
|
import { Component, EventEmitter, Input, Output, } from '@angular/core';
|
||||||
import { getComponentByWorkflowTaskOption } from './claimed-task-actions-decorator';
|
import { getComponentByWorkflowTaskOption } from './claimed-task-actions-decorator';
|
||||||
import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model';
|
import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model';
|
||||||
import { MyDSpaceActionsResult } from '../../mydspace-actions';
|
import { MyDSpaceActionsResult } from '../../mydspace-actions';
|
||||||
@@ -16,7 +16,7 @@ import { GenericConstructor } from '../../../../core/shared/generic-constructor'
|
|||||||
* Component for loading a ClaimedTaskAction component depending on the "option" input
|
* Component for loading a ClaimedTaskAction component depending on the "option" input
|
||||||
* Passes on the ClaimedTask to the component and subscribes to the processCompleted output
|
* Passes on the ClaimedTask to the component and subscribes to the processCompleted output
|
||||||
*/
|
*/
|
||||||
export class ClaimedTaskActionsLoaderComponent extends AbstractComponentLoaderComponent<ClaimedTaskActionsAbstractComponent> implements OnInit, OnChanges {
|
export class ClaimedTaskActionsLoaderComponent extends AbstractComponentLoaderComponent<ClaimedTaskActionsAbstractComponent> {
|
||||||
/**
|
/**
|
||||||
* The item object that belonging to the ClaimedTask object
|
* The item object that belonging to the ClaimedTask object
|
||||||
*/
|
*/
|
||||||
@@ -46,12 +46,16 @@ export class ClaimedTaskActionsLoaderComponent extends AbstractComponentLoaderCo
|
|||||||
/**
|
/**
|
||||||
* The list of input and output names for the dynamic component
|
* The list of input and output names for the dynamic component
|
||||||
*/
|
*/
|
||||||
protected inAndOutputNames: (keyof this)[] = [
|
protected inputNames: (keyof this & string)[] = [
|
||||||
...this.inAndOutputNames,
|
...this.inputNames,
|
||||||
'item',
|
'item',
|
||||||
'object',
|
'object',
|
||||||
'option',
|
'option',
|
||||||
'workflowitem',
|
'workflowitem',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected outputNames: (keyof this & string)[] = [
|
||||||
|
...this.outputNames,
|
||||||
'processCompleted',
|
'processCompleted',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
import { ChangeDetectorRef, Component, EventEmitter, Input, Output, SimpleChanges } from '@angular/core';
|
import { ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
import { combineLatest, Observable, of as observableOf } from 'rxjs';
|
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
import { ListableObject } from '../listable-object.model';
|
import { ListableObject } from '../listable-object.model';
|
||||||
import { ViewMode } from '../../../../core/shared/view-mode.model';
|
import { ViewMode } from '../../../../core/shared/view-mode.model';
|
||||||
@@ -74,8 +73,8 @@ export class ListableObjectComponentLoaderComponent extends AbstractComponentLoa
|
|||||||
/**
|
/**
|
||||||
* The list of input and output names for the dynamic component
|
* The list of input and output names for the dynamic component
|
||||||
*/
|
*/
|
||||||
protected inAndOutputNames: (keyof this)[] = [
|
protected inputNames: (keyof this & string)[] = [
|
||||||
...this.inAndOutputNames,
|
...this.inputNames,
|
||||||
'object',
|
'object',
|
||||||
'index',
|
'index',
|
||||||
'linkType',
|
'linkType',
|
||||||
@@ -84,6 +83,10 @@ export class ListableObjectComponentLoaderComponent extends AbstractComponentLoa
|
|||||||
'showThumbnails',
|
'showThumbnails',
|
||||||
'viewMode',
|
'viewMode',
|
||||||
'value',
|
'value',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected outputNames: (keyof this & string)[] = [
|
||||||
|
...this.outputNames,
|
||||||
'contentChange',
|
'contentChange',
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -94,17 +97,16 @@ export class ListableObjectComponentLoaderComponent extends AbstractComponentLoa
|
|||||||
super(themeService);
|
super(themeService);
|
||||||
}
|
}
|
||||||
|
|
||||||
public instantiateComponent(changes?: SimpleChanges): void {
|
public instantiateComponent(): void {
|
||||||
super.instantiateComponent(changes);
|
super.instantiateComponent();
|
||||||
if ((this.compRef.instance as any).reloadedObject) {
|
if ((this.compRef.instance as any).reloadedObject) {
|
||||||
combineLatest([
|
(this.compRef.instance as any).reloadedObject.pipe(
|
||||||
observableOf(changes),
|
take(1),
|
||||||
(this.compRef.instance as any).reloadedObject.pipe(take(1)) as Observable<DSpaceObject>,
|
).subscribe((reloadedObject: DSpaceObject) => {
|
||||||
]).subscribe(([simpleChanges, reloadedObject]: [SimpleChanges, DSpaceObject]) => {
|
|
||||||
if (reloadedObject) {
|
if (reloadedObject) {
|
||||||
this.compRef.destroy();
|
this.destroyComponentInstance();
|
||||||
this.object = reloadedObject;
|
this.object = reloadedObject;
|
||||||
this.instantiateComponent(simpleChanges);
|
this.instantiateComponent();
|
||||||
this.cdr.detectChanges();
|
this.cdr.detectChanges();
|
||||||
this.contentChange.emit(reloadedObject);
|
this.contentChange.emit(reloadedObject);
|
||||||
}
|
}
|
||||||
|
@@ -24,8 +24,8 @@ export class AdvancedWorkflowActionsLoaderComponent extends AbstractComponentLoa
|
|||||||
*/
|
*/
|
||||||
@Input() type: string;
|
@Input() type: string;
|
||||||
|
|
||||||
protected inAndOutputNames: (keyof this)[] = [
|
protected inputNames: (keyof this & string)[] = [
|
||||||
...this.inAndOutputNames,
|
...this.inputNames,
|
||||||
'type',
|
'type',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user