diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts index d98624f0c5..bac39723ef 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts @@ -255,7 +255,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo getSucceededRemoteData(), getRemoteDataPayload(), map((leftItem: Item) => { - return new ReorderableRelationship(relationship, leftItem.uuid !== this.item.uuid) + return new ReorderableRelationship(relationship, leftItem.uuid !== this.item.uuid, this.relationshipService) }), ) ) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.ts index 29ba29e68f..8379c4873e 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.ts @@ -1,31 +1,55 @@ -import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; -import { Item } from '../../../../../core/shared/item.model'; -import { MetadataRepresentation } from '../../../../../core/shared/metadata-representation/metadata-representation.model'; -import { getAllSucceededRemoteData, getRemoteDataPayload } from '../../../../../core/shared/operators'; -import { hasValue, isNotEmpty } from '../../../../empty.util'; -import { Subscription } from 'rxjs'; -import { filter } from 'rxjs/operators'; -import { Relationship } from '../../../../../core/shared/item-relationships/relationship.model'; -import { MetadataValue } from '../../../../../core/shared/metadata.models'; -import { ItemMetadataRepresentation } from '../../../../../core/shared/metadata-representation/item/item-metadata-representation.model'; -import { RelationshipOptions } from '../../models/relationship-options.model'; -import { RemoveRelationshipAction } from '../relation-lookup-modal/relationship.actions'; -import { SelectableListService } from '../../../../object-list/selectable-list/selectable-list.service'; +import { Component, EventEmitter, Input, OnChanges, OnDestroy } from '@angular/core'; +import { AbstractControl, FormControl } from '@angular/forms'; +import { DynamicFormControlEvent } from '@ng-dynamic-forms/core'; import { Store } from '@ngrx/store'; +import { Observable, of as observableOf, Subject, Subscription } from 'rxjs'; +import { filter } from 'rxjs/operators'; import { AppState } from '../../../../../app.reducer'; +import { RelationshipService } from '../../../../../core/data/relationship.service'; +import { RemoteData } from '../../../../../core/data/remote-data'; +import { Relationship } from '../../../../../core/shared/item-relationships/relationship.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { ItemMetadataRepresentation } from '../../../../../core/shared/metadata-representation/item/item-metadata-representation.model'; +import { MetadataRepresentation } from '../../../../../core/shared/metadata-representation/metadata-representation.model'; +import { MetadataValue } from '../../../../../core/shared/metadata.models'; +import { + getAllSucceededRemoteData, + getRemoteDataPayload, + getSucceededRemoteData +} from '../../../../../core/shared/operators'; +import { hasValue, isNotEmpty } from '../../../../empty.util'; import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model'; +import { SelectableListService } from '../../../../object-list/selectable-list/selectable-list.service'; +import { FormFieldMetadataValueObject } from '../../models/form-field-metadata-value.model'; +import { RelationshipOptions } from '../../models/relationship-options.model'; +import { DynamicConcatModel } from '../models/ds-dynamic-concat.model'; +import { RemoveRelationshipAction } from '../relation-lookup-modal/relationship.actions'; export abstract class Reorderable { + constructor(public oldIndex?: number, public newIndex?: number) { } abstract getId(): string; + abstract getPlace(): number; + + abstract update(): Observable; + + get hasMoved(): boolean { + return this.oldIndex !== this.newIndex + } } -export class ReorderableMetadataValue extends Reorderable { +export class ReorderableFormFieldMetadataValue extends Reorderable { - constructor(public metadataValue: MetadataValue, oldIndex?: number, newIndex?: number) { + constructor( + public metadataValue: FormFieldMetadataValueObject, + public model: DynamicConcatModel, + public control: FormControl, + oldIndex?: number, + newIndex?: number + ) { super(oldIndex, newIndex); this.metadataValue = metadataValue; } @@ -43,11 +67,19 @@ export class ReorderableMetadataValue extends Reorderable { return this.metadataValue.place; } + update(): Observable { + this.metadataValue.place = this.newIndex; + this.model.valueUpdates.next(this.metadataValue as any); + console.log('this.control.value', this.control.value); + this.oldIndex = this.newIndex; + return observableOf(this.metadataValue); + } + } export class ReorderableRelationship extends Reorderable { - constructor(public relationship: Relationship, public useLeftItem: boolean, oldIndex?: number, newIndex?: number) { + constructor(public relationship: Relationship, public useLeftItem: boolean, protected relationshipService: RelationshipService, oldIndex?: number, newIndex?: number) { super(oldIndex, newIndex); this.relationship = relationship; this.useLeftItem = useLeftItem; @@ -64,21 +96,17 @@ export class ReorderableRelationship extends Reorderable { return this.relationship.leftPlace } } -} -export class ReorderableMetadata extends Reorderable { - metadata: MetadataValue; - constructor(metadata: MetadataValue, oldIndex?: number, newIndex?: number) { - super(oldIndex, newIndex); - this.metadata = metadata; - } + update(): Observable> { + const updatedRelationship$ = this.relationshipService.updatePlace(this); - getId(): string { - return this.metadata.uuid; - } + updatedRelationship$.pipe( + getSucceededRemoteData() + ).subscribe(() => { + this.oldIndex = this.newIndex; + }); - getPlace(): number { - return this.metadata.place + return updatedRelationship$; } } @@ -120,7 +148,7 @@ export class ExistingMetadataListElementComponent implements OnChanges, OnDestro const relationMD: MetadataValue = this.submissionItem.firstMetadata(this.relationshipOptions.metadataField, { value: this.relatedItem.uuid }); if (hasValue(relationMD)) { const metadataRepresentationMD: MetadataValue = this.submissionItem.firstMetadata(this.metadataFields, { authority: relationMD.authority }); - this.metadataRepresentation = Object.assign( + this.metadataRepresentation = Object.assign( new ItemMetadataRepresentation(metadataRepresentationMD), this.relatedItem ) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component.ts index 1843beb448..f2af5c6d7e 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component.ts @@ -1,12 +1,11 @@ import { CdkDragDrop } from '@angular/cdk/drag-drop'; import { Component, EventEmitter, Input, NgZone, OnInit, Output, QueryList } from '@angular/core'; -import { FormGroup } from '@angular/forms'; +import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; import { DynamicFormArrayComponent, DynamicFormArrayGroupModel, - DynamicFormArrayModel, DynamicFormControlCustomEvent, - DynamicFormControlEvent, DynamicFormControlModel, + DynamicFormControlEvent, DynamicFormLayout, DynamicFormLayoutService, DynamicFormService, @@ -14,22 +13,23 @@ import { DynamicTemplateDirective } from '@ng-dynamic-forms/core'; import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs'; -import { map, switchMap, take, tap } from 'rxjs/operators'; +import { map, switchMap, take } from 'rxjs/operators'; import { RelationshipService } from '../../../../../../core/data/relationship.service'; import { RemoteData } from '../../../../../../core/data/remote-data'; import { Relationship } from '../../../../../../core/shared/item-relationships/relationship.model'; import { Item } from '../../../../../../core/shared/item.model'; import { MetadataValue } from '../../../../../../core/shared/metadata.models'; import { - getAllSucceededRemoteData, - getRemoteDataPayload, getSucceededRemoteData + getRemoteDataPayload, + getSucceededRemoteData } from '../../../../../../core/shared/operators'; import { SubmissionObject } from '../../../../../../core/submission/models/submission-object.model'; import { SubmissionObjectDataService } from '../../../../../../core/submission/submission-object-data.service'; import { hasValue, isNotEmpty } from '../../../../../empty.util'; import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model'; import { - Reorderable, ReorderableMetadataValue, + Reorderable, + ReorderableFormFieldMetadataValue, ReorderableRelationship } from '../../existing-metadata-list-element/existing-metadata-list-element.component'; import { DynamicConcatModel } from '../ds-dynamic-concat.model'; @@ -69,6 +69,7 @@ export class DsDynamicFormArrayComponent extends DynamicFormArrayComponent imple } ngOnInit(): void { + console.log('this.group.controls[this.model.id]', this.control); this.submissionObjectService .findById(this.model.submissionId).pipe( getSucceededRemoteData(), @@ -84,81 +85,91 @@ export class DsDynamicFormArrayComponent extends DynamicFormArrayComponent imple this.updateReorderables(); } - private updateReorderables(): void { - const reorderable$arr: Array> = this.model.groups - .slice(1) // disregard the first group, it is always empty to ensure the first field remains empty - .map((group: DynamicFormArrayGroupModel, index: number) => { - const formFieldMetadataValue: FormFieldMetadataValueObject = (group.group[0] as DynamicConcatModel).value as FormFieldMetadataValueObject; - if (hasValue(formFieldMetadataValue)) { - const value = Object.assign(new MetadataValue(), { - value: formFieldMetadataValue.display, - language: formFieldMetadataValue.language, - place: formFieldMetadataValue.place, - authority: formFieldMetadataValue.authority, - confidence: formFieldMetadataValue.confidence - }); - if (value.isVirtual) { - return this.relationshipService.findById(value.virtualValue) - .pipe( - getSucceededRemoteData(), - getRemoteDataPayload(), - switchMap((relationship: Relationship) => - relationship.leftItem.pipe( - getSucceededRemoteData(), - getRemoteDataPayload(), - map((leftItem: Item) => { - return new ReorderableRelationship( - relationship, - leftItem.uuid !== this.submissionItem.uuid, - index, - index - ); - }), + private updateReorderables(): void { + this.zone.runOutsideAngular(() => { + const reorderable$arr: Array> = this.model.groups + .map((group, index) => [group, (this.control as any).controls[index]]) + .slice(1) // disregard the first group, it is always empty to ensure the first field remains empty + .map(([group, control]: [DynamicFormArrayGroupModel, AbstractControl], index: number) => { + const model = group.group[0] as DynamicConcatModel; + let formFieldMetadataValue: FormFieldMetadataValueObject = model.value as FormFieldMetadataValueObject; + if (hasValue(formFieldMetadataValue)) { + const metadataValue = Object.assign(new MetadataValue(), { + value: formFieldMetadataValue.display, + language: formFieldMetadataValue.language, + place: formFieldMetadataValue.place, + authority: formFieldMetadataValue.authority, + confidence: formFieldMetadataValue.confidence + }); + if (metadataValue.isVirtual) { + return this.relationshipService.findById(metadataValue.virtualValue) + .pipe( + getSucceededRemoteData(), + getRemoteDataPayload(), + switchMap((relationship: Relationship) => + relationship.leftItem.pipe( + getSucceededRemoteData(), + getRemoteDataPayload(), + map((leftItem: Item) => { + return new ReorderableRelationship( + relationship, + leftItem.uuid !== this.submissionItem.uuid, + this.relationshipService, + index, + index + ); + }), + ) ) - ) - ); + ); + } else { + if (typeof formFieldMetadataValue === 'string') { + formFieldMetadataValue = Object.assign(new FormFieldMetadataValueObject(), { + value: formFieldMetadataValue, + display: formFieldMetadataValue, + place: index, + }); + } + return observableOf(new ReorderableFormFieldMetadataValue(formFieldMetadataValue, model as any, control as FormControl, index, index)); + } } else { - return observableOf(new ReorderableMetadataValue(value, index, index)); + formFieldMetadataValue = Object.assign(new FormFieldMetadataValueObject(), { + value: '', + display: '', + place: index, + }); + return observableOf(new ReorderableFormFieldMetadataValue(formFieldMetadataValue, model as any, control as FormControl, index, index)); } - } else { - const value = Object.assign(new MetadataValue(), { - value: '', - place: index, - }); - return observableOf(new ReorderableMetadataValue(value, index, index)); - } - }); + }); - observableCombineLatest(reorderable$arr) - .subscribe((reorderables: Reorderable[]) => { - if (isNotEmpty(this.reorderables)) { - reorderables.forEach((newReorderable: Reorderable) => { - const match = this.reorderables.find((reo: Reorderable) => reo.getId() === newReorderable.getId()); - if (hasValue(match)) { - newReorderable.oldIndex = match.newIndex; + observableCombineLatest(reorderable$arr) + .subscribe((reorderables: Reorderable[]) => { + if (isNotEmpty(this.reorderables)) { + reorderables.forEach((newReorderable: Reorderable) => { + const match = this.reorderables.find((reo: Reorderable) => reo.getId() === newReorderable.getId()); + if (hasValue(match)) { + newReorderable.oldIndex = match.newIndex; + } + }) + } + this.reorderables = reorderables; + + this.reorderables.forEach((reorderable: Reorderable) => { + if (reorderable.hasMoved) { + console.log('reorderable moved', reorderable, reorderable.getPlace()); + reorderable.update().pipe(take(1)).subscribe((v) => { + console.log('reorderable updated', reorderable, reorderable.getPlace()); + }); } }) - } - this.reorderables = reorderables; - console.log('this.reorderables', this.reorderables); - }); + }); + }) + } moveSelection(event: CdkDragDrop) { - this.model.moveGroup(event.previousIndex,event.currentIndex - event.previousIndex); + this.model.moveGroup(event.previousIndex, event.currentIndex - event.previousIndex); this.updateReorderables(); - - // this.zone.runOutsideAngular(() => { - - // return observableCombineLatest(reorderables.map((rel: ReorderableRelationship) => { - // if (rel.oldIndex !== rel.newIndex) { - // return this.relationshipService.updatePlace(rel); - // } else { - // return observableOf(undefined); - // } - // }) - // ).pipe(getSucceededRemoteData()).subscribe(); - // }) } }