store reordered relationships to the server

This commit is contained in:
Art Lowel
2019-12-10 15:40:56 +01:00
parent b728463e56
commit 453a2919d1
3 changed files with 141 additions and 102 deletions

View File

@@ -255,7 +255,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
getSucceededRemoteData(), getSucceededRemoteData(),
getRemoteDataPayload(), getRemoteDataPayload(),
map((leftItem: Item) => { map((leftItem: Item) => {
return new ReorderableRelationship(relationship, leftItem.uuid !== this.item.uuid) return new ReorderableRelationship(relationship, leftItem.uuid !== this.item.uuid, this.relationshipService)
}), }),
) )
) )

View File

@@ -1,31 +1,55 @@
import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, OnDestroy } from '@angular/core';
import { Item } from '../../../../../core/shared/item.model'; import { AbstractControl, FormControl } from '@angular/forms';
import { MetadataRepresentation } from '../../../../../core/shared/metadata-representation/metadata-representation.model'; import { DynamicFormControlEvent } from '@ng-dynamic-forms/core';
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 { Store } from '@ngrx/store'; 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 { 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 { 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 { export abstract class Reorderable {
constructor(public oldIndex?: number, public newIndex?: number) { constructor(public oldIndex?: number, public newIndex?: number) {
} }
abstract getId(): string; abstract getId(): string;
abstract getPlace(): number; abstract getPlace(): number;
abstract update(): Observable<any>;
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); super(oldIndex, newIndex);
this.metadataValue = metadataValue; this.metadataValue = metadataValue;
} }
@@ -43,11 +67,19 @@ export class ReorderableMetadataValue extends Reorderable {
return this.metadataValue.place; return this.metadataValue.place;
} }
update(): Observable<FormFieldMetadataValueObject> {
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 { 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); super(oldIndex, newIndex);
this.relationship = relationship; this.relationship = relationship;
this.useLeftItem = useLeftItem; this.useLeftItem = useLeftItem;
@@ -64,21 +96,17 @@ export class ReorderableRelationship extends Reorderable {
return this.relationship.leftPlace return this.relationship.leftPlace
} }
} }
}
export class ReorderableMetadata extends Reorderable {
metadata: MetadataValue;
constructor(metadata: MetadataValue, oldIndex?: number, newIndex?: number) { update(): Observable<RemoteData<Relationship>> {
super(oldIndex, newIndex); const updatedRelationship$ = this.relationshipService.updatePlace(this);
this.metadata = metadata;
}
getId(): string { updatedRelationship$.pipe(
return this.metadata.uuid; getSucceededRemoteData()
} ).subscribe(() => {
this.oldIndex = this.newIndex;
});
getPlace(): number { return updatedRelationship$;
return this.metadata.place
} }
} }
@@ -120,7 +148,7 @@ export class ExistingMetadataListElementComponent implements OnChanges, OnDestro
const relationMD: MetadataValue = this.submissionItem.firstMetadata(this.relationshipOptions.metadataField, { value: this.relatedItem.uuid }); const relationMD: MetadataValue = this.submissionItem.firstMetadata(this.relationshipOptions.metadataField, { value: this.relatedItem.uuid });
if (hasValue(relationMD)) { if (hasValue(relationMD)) {
const metadataRepresentationMD: MetadataValue = this.submissionItem.firstMetadata(this.metadataFields, { authority: relationMD.authority }); const metadataRepresentationMD: MetadataValue = this.submissionItem.firstMetadata(this.metadataFields, { authority: relationMD.authority });
this.metadataRepresentation = Object.assign( this.metadataRepresentation = Object.assign(
new ItemMetadataRepresentation(metadataRepresentationMD), new ItemMetadataRepresentation(metadataRepresentationMD),
this.relatedItem this.relatedItem
) )

View File

@@ -1,12 +1,11 @@
import { CdkDragDrop } from '@angular/cdk/drag-drop'; import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { Component, EventEmitter, Input, NgZone, OnInit, Output, QueryList } from '@angular/core'; 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 { import {
DynamicFormArrayComponent, DynamicFormArrayComponent,
DynamicFormArrayGroupModel, DynamicFormArrayGroupModel,
DynamicFormArrayModel,
DynamicFormControlCustomEvent, DynamicFormControlCustomEvent,
DynamicFormControlEvent, DynamicFormControlModel, DynamicFormControlEvent,
DynamicFormLayout, DynamicFormLayout,
DynamicFormLayoutService, DynamicFormLayoutService,
DynamicFormService, DynamicFormService,
@@ -14,22 +13,23 @@ import {
DynamicTemplateDirective DynamicTemplateDirective
} from '@ng-dynamic-forms/core'; } from '@ng-dynamic-forms/core';
import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs'; 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 { RelationshipService } from '../../../../../../core/data/relationship.service';
import { RemoteData } from '../../../../../../core/data/remote-data'; import { RemoteData } from '../../../../../../core/data/remote-data';
import { Relationship } from '../../../../../../core/shared/item-relationships/relationship.model'; import { Relationship } from '../../../../../../core/shared/item-relationships/relationship.model';
import { Item } from '../../../../../../core/shared/item.model'; import { Item } from '../../../../../../core/shared/item.model';
import { MetadataValue } from '../../../../../../core/shared/metadata.models'; import { MetadataValue } from '../../../../../../core/shared/metadata.models';
import { import {
getAllSucceededRemoteData, getRemoteDataPayload,
getRemoteDataPayload, getSucceededRemoteData getSucceededRemoteData
} from '../../../../../../core/shared/operators'; } from '../../../../../../core/shared/operators';
import { SubmissionObject } from '../../../../../../core/submission/models/submission-object.model'; import { SubmissionObject } from '../../../../../../core/submission/models/submission-object.model';
import { SubmissionObjectDataService } from '../../../../../../core/submission/submission-object-data.service'; import { SubmissionObjectDataService } from '../../../../../../core/submission/submission-object-data.service';
import { hasValue, isNotEmpty } from '../../../../../empty.util'; import { hasValue, isNotEmpty } from '../../../../../empty.util';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model'; import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
import { import {
Reorderable, ReorderableMetadataValue, Reorderable,
ReorderableFormFieldMetadataValue,
ReorderableRelationship ReorderableRelationship
} from '../../existing-metadata-list-element/existing-metadata-list-element.component'; } from '../../existing-metadata-list-element/existing-metadata-list-element.component';
import { DynamicConcatModel } from '../ds-dynamic-concat.model'; import { DynamicConcatModel } from '../ds-dynamic-concat.model';
@@ -69,6 +69,7 @@ export class DsDynamicFormArrayComponent extends DynamicFormArrayComponent imple
} }
ngOnInit(): void { ngOnInit(): void {
console.log('this.group.controls[this.model.id]', this.control);
this.submissionObjectService this.submissionObjectService
.findById(this.model.submissionId).pipe( .findById(this.model.submissionId).pipe(
getSucceededRemoteData(), getSucceededRemoteData(),
@@ -84,81 +85,91 @@ export class DsDynamicFormArrayComponent extends DynamicFormArrayComponent imple
this.updateReorderables(); this.updateReorderables();
} }
private updateReorderables(): void { private updateReorderables(): void {
const reorderable$arr: Array<Observable<Reorderable>> = this.model.groups this.zone.runOutsideAngular(() => {
.slice(1) // disregard the first group, it is always empty to ensure the first field remains empty const reorderable$arr: Array<Observable<Reorderable>> = this.model.groups
.map((group: DynamicFormArrayGroupModel, index: number) => { .map((group, index) => [group, (this.control as any).controls[index]])
const formFieldMetadataValue: FormFieldMetadataValueObject = (group.group[0] as DynamicConcatModel).value as FormFieldMetadataValueObject; .slice(1) // disregard the first group, it is always empty to ensure the first field remains empty
if (hasValue(formFieldMetadataValue)) { .map(([group, control]: [DynamicFormArrayGroupModel, AbstractControl], index: number) => {
const value = Object.assign(new MetadataValue(), { const model = group.group[0] as DynamicConcatModel;
value: formFieldMetadataValue.display, let formFieldMetadataValue: FormFieldMetadataValueObject = model.value as FormFieldMetadataValueObject;
language: formFieldMetadataValue.language, if (hasValue(formFieldMetadataValue)) {
place: formFieldMetadataValue.place, const metadataValue = Object.assign(new MetadataValue(), {
authority: formFieldMetadataValue.authority, value: formFieldMetadataValue.display,
confidence: formFieldMetadataValue.confidence language: formFieldMetadataValue.language,
}); place: formFieldMetadataValue.place,
if (value.isVirtual) { authority: formFieldMetadataValue.authority,
return this.relationshipService.findById(value.virtualValue) confidence: formFieldMetadataValue.confidence
.pipe( });
getSucceededRemoteData(), if (metadataValue.isVirtual) {
getRemoteDataPayload(), return this.relationshipService.findById(metadataValue.virtualValue)
switchMap((relationship: Relationship) => .pipe(
relationship.leftItem.pipe( getSucceededRemoteData(),
getSucceededRemoteData(), getRemoteDataPayload(),
getRemoteDataPayload(), switchMap((relationship: Relationship) =>
map((leftItem: Item) => { relationship.leftItem.pipe(
return new ReorderableRelationship( getSucceededRemoteData(),
relationship, getRemoteDataPayload(),
leftItem.uuid !== this.submissionItem.uuid, map((leftItem: Item) => {
index, return new ReorderableRelationship(
index 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 { } 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) observableCombineLatest(reorderable$arr)
.subscribe((reorderables: Reorderable[]) => { .subscribe((reorderables: Reorderable[]) => {
if (isNotEmpty(this.reorderables)) { if (isNotEmpty(this.reorderables)) {
reorderables.forEach((newReorderable: Reorderable) => { reorderables.forEach((newReorderable: Reorderable) => {
const match = this.reorderables.find((reo: Reorderable) => reo.getId() === newReorderable.getId()); const match = this.reorderables.find((reo: Reorderable) => reo.getId() === newReorderable.getId());
if (hasValue(match)) { if (hasValue(match)) {
newReorderable.oldIndex = match.newIndex; 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<Relationship>) { moveSelection(event: CdkDragDrop<Relationship>) {
this.model.moveGroup(event.previousIndex,event.currentIndex - event.previousIndex); this.model.moveGroup(event.previousIndex, event.currentIndex - event.previousIndex);
this.updateReorderables(); 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();
// })
} }
} }