mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
switch to patch for reorderin
This commit is contained in:
@@ -48,7 +48,9 @@ export abstract class Reorderable {
|
|||||||
/**
|
/**
|
||||||
* Update the Reorderable
|
* Update the Reorderable
|
||||||
*/
|
*/
|
||||||
abstract update(): Observable<any>;
|
update(): void {
|
||||||
|
this.oldIndex = this.newIndex;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the oldIndex of this Reorderable
|
* Returns true if the oldIndex of this Reorderable
|
||||||
@@ -95,14 +97,6 @@ export class ReorderableFormFieldMetadataValue extends Reorderable {
|
|||||||
return this.metadataValue.place;
|
return this.metadataValue.place;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the Reorderable
|
|
||||||
*/
|
|
||||||
update(): Observable<FormFieldMetadataValueObject> {
|
|
||||||
this.oldIndex = this.newIndex;
|
|
||||||
return observableOf(this.metadataValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,23 +134,6 @@ export class ReorderableRelationship extends Reorderable {
|
|||||||
return this.relationship.leftPlace
|
return this.relationship.leftPlace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the Reorderable
|
|
||||||
*/
|
|
||||||
update(): Observable<RemoteData<Relationship>> {
|
|
||||||
this.store.dispatch(new UpdateRelationshipAction(this.relationship, this.submissionID))
|
|
||||||
const updatedRelationship$ = this.relationshipService.updatePlace(this).pipe(
|
|
||||||
getSucceededRemoteData(),
|
|
||||||
);
|
|
||||||
|
|
||||||
updatedRelationship$.subscribe(() => {
|
|
||||||
this.oldIndex = this.newIndex;
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
return updatedRelationship$;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -35,8 +35,8 @@
|
|||||||
[model]="_model"
|
[model]="_model"
|
||||||
[templates]="templates"
|
[templates]="templates"
|
||||||
[ngClass]="[getClass('element', 'host', _model), getClass('grid', 'host', _model)]"
|
[ngClass]="[getClass('element', 'host', _model), getClass('grid', 'host', _model)]"
|
||||||
(dfBlur)="update(idx)"
|
(dfBlur)="update($event, idx)"
|
||||||
(dfChange)="update(idx)"
|
(dfChange)="update($event, idx)"
|
||||||
(dfFocus)="onFocus($event)"
|
(dfFocus)="onFocus($event)"
|
||||||
(ngbEvent)="onCustomEvent($event, null, true)"></ds-dynamic-form-control-container>
|
(ngbEvent)="onCustomEvent($event, null, true)"></ds-dynamic-form-control-container>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@@ -1,60 +1,25 @@
|
|||||||
import { CdkDragDrop } from '@angular/cdk/drag-drop';
|
import { CdkDragDrop } from '@angular/cdk/drag-drop';
|
||||||
import {
|
import { Component, EventEmitter, Input, Output, QueryList } from '@angular/core';
|
||||||
ChangeDetectorRef,
|
import { FormGroup } from '@angular/forms';
|
||||||
Component,
|
|
||||||
EventEmitter,
|
|
||||||
Input,
|
|
||||||
NgZone,
|
|
||||||
OnInit,
|
|
||||||
Output,
|
|
||||||
QueryList
|
|
||||||
} from '@angular/core';
|
|
||||||
import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
|
|
||||||
import {
|
import {
|
||||||
DynamicFormArrayComponent,
|
DynamicFormArrayComponent,
|
||||||
DynamicFormArrayGroupModel,
|
|
||||||
DynamicFormControlCustomEvent,
|
DynamicFormControlCustomEvent,
|
||||||
DynamicFormControlEvent, DynamicFormControlEventType,
|
DynamicFormControlEvent,
|
||||||
|
DynamicFormControlEventType,
|
||||||
DynamicFormLayout,
|
DynamicFormLayout,
|
||||||
DynamicFormLayoutService,
|
DynamicFormLayoutService,
|
||||||
DynamicFormService,
|
|
||||||
DynamicFormValidationService,
|
DynamicFormValidationService,
|
||||||
DynamicTemplateDirective
|
DynamicTemplateDirective
|
||||||
} from '@ng-dynamic-forms/core';
|
} from '@ng-dynamic-forms/core';
|
||||||
import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs';
|
|
||||||
import { map, switchMap, take, tap, filter } 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 { Relationship } from '../../../../../../core/shared/item-relationships/relationship.model';
|
||||||
import { Item } from '../../../../../../core/shared/item.model';
|
|
||||||
import { MetadataValue } from '../../../../../../core/shared/metadata.models';
|
|
||||||
import {
|
|
||||||
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,
|
|
||||||
ReorderableFormFieldMetadataValue,
|
|
||||||
ReorderableRelationship
|
|
||||||
} from '../../existing-metadata-list-element/existing-metadata-list-element.component';
|
|
||||||
import { DynamicConcatModel } from '../ds-dynamic-concat.model';
|
|
||||||
import { DynamicRowArrayModel } from '../ds-dynamic-row-array-model';
|
import { DynamicRowArrayModel } from '../ds-dynamic-row-array-model';
|
||||||
import { Store } from '@ngrx/store';
|
|
||||||
import { SubmissionService } from '../../../../../../submission/submission.service';
|
|
||||||
import { AppState } from '../../../../../../app.reducer';
|
|
||||||
import { followLink } from '../../../../../utils/follow-link-config.model';
|
|
||||||
import { ObjectCacheService } from '../../../../../../core/cache/object-cache.service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-dynamic-form-array',
|
selector: 'ds-dynamic-form-array',
|
||||||
templateUrl: './dynamic-form-array.component.html',
|
templateUrl: './dynamic-form-array.component.html',
|
||||||
styleUrls: ['./dynamic-form-array.component.scss']
|
styleUrls: ['./dynamic-form-array.component.scss']
|
||||||
})
|
})
|
||||||
export class DsDynamicFormArrayComponent extends DynamicFormArrayComponent implements OnInit {
|
export class DsDynamicFormArrayComponent extends DynamicFormArrayComponent {
|
||||||
|
|
||||||
@Input() bindId = true;
|
@Input() bindId = true;
|
||||||
@Input() group: FormGroup;
|
@Input() group: FormGroup;
|
||||||
@@ -68,169 +33,37 @@ export class DsDynamicFormArrayComponent extends DynamicFormArrayComponent imple
|
|||||||
@Output('dfFocus') focus: EventEmitter<DynamicFormControlEvent> = new EventEmitter<DynamicFormControlEvent>();
|
@Output('dfFocus') focus: EventEmitter<DynamicFormControlEvent> = new EventEmitter<DynamicFormControlEvent>();
|
||||||
@Output('ngbEvent') customEvent: EventEmitter<DynamicFormControlCustomEvent> = new EventEmitter();
|
@Output('ngbEvent') customEvent: EventEmitter<DynamicFormControlCustomEvent> = new EventEmitter();
|
||||||
|
|
||||||
private submissionItem: Item;
|
|
||||||
private reorderables: Reorderable[] = [];
|
|
||||||
|
|
||||||
/* tslint:enable:no-output-rename */
|
/* tslint:enable:no-output-rename */
|
||||||
|
|
||||||
constructor(protected layoutService: DynamicFormLayoutService,
|
constructor(protected layoutService: DynamicFormLayoutService,
|
||||||
protected validationService: DynamicFormValidationService,
|
protected validationService: DynamicFormValidationService,
|
||||||
protected objectCacheService: ObjectCacheService,
|
|
||||||
protected relationshipService: RelationshipService,
|
|
||||||
protected changeDetectorRef: ChangeDetectorRef,
|
|
||||||
protected submissionObjectService: SubmissionObjectDataService,
|
|
||||||
protected zone: NgZone,
|
|
||||||
protected formService: DynamicFormService,
|
|
||||||
private submissionService: SubmissionService,
|
|
||||||
private store: Store<AppState>,
|
|
||||||
) {
|
) {
|
||||||
super(layoutService, validationService);
|
super(layoutService, validationService);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.submissionObjectService
|
|
||||||
.findById(this.model.submissionId, followLink('item')).pipe(
|
|
||||||
getSucceededRemoteData(),
|
|
||||||
getRemoteDataPayload(),
|
|
||||||
switchMap((submissionObject: SubmissionObject) => (submissionObject.item as Observable<RemoteData<Item>>)
|
|
||||||
.pipe(
|
|
||||||
getSucceededRemoteData(),
|
|
||||||
getRemoteDataPayload()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
).subscribe((item) => {
|
|
||||||
this.submissionItem = item;
|
|
||||||
this.updateReorderables(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private updateReorderables(shouldPropagateChanges = true): void {
|
|
||||||
this.zone.runOutsideAngular(() => {
|
|
||||||
let groups = this.model.groups.map((group, index) => [group, (this.control as any).controls[index]]);
|
|
||||||
groups = [...groups, groups[0]];
|
|
||||||
const reorderable$arr: Array<Observable<Reorderable>> = groups
|
|
||||||
.filter(([group, control], index) => index > 0 && hasValue((group.group[0] as any).value)) // 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, followLink('leftItem'))
|
|
||||||
.pipe(
|
|
||||||
filter((relRD: RemoteData<Relationship>) => hasValue(relRD.payload)),
|
|
||||||
take(1),
|
|
||||||
getRemoteDataPayload(),
|
|
||||||
switchMap((relationship: Relationship) =>
|
|
||||||
relationship.leftItem.pipe(
|
|
||||||
filter((itemRD: RemoteData<Item>) => hasValue(itemRD.payload)),
|
|
||||||
take(1),
|
|
||||||
getRemoteDataPayload(),
|
|
||||||
map((leftItem: Item) => {
|
|
||||||
return new ReorderableRelationship(
|
|
||||||
relationship,
|
|
||||||
leftItem.uuid !== this.submissionItem.uuid,
|
|
||||||
this.relationshipService,
|
|
||||||
this.store,
|
|
||||||
this.model.submissionId,
|
|
||||||
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, group, index, index));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
formFieldMetadataValue = Object.assign(new FormFieldMetadataValueObject(), {
|
|
||||||
value: '',
|
|
||||||
display: '',
|
|
||||||
place: index,
|
|
||||||
});
|
|
||||||
return observableOf(new ReorderableFormFieldMetadataValue(formFieldMetadataValue, model as any, control as FormControl, group, index, index));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
observableCombineLatest(reorderable$arr)
|
|
||||||
.subscribe((reorderables: Reorderable[]) => {
|
|
||||||
reorderables.forEach((newReorderable: Reorderable) => {
|
|
||||||
const match = this.reorderables.find((reo: Reorderable) => reo.getId() === newReorderable.getId());
|
|
||||||
if (hasValue(match)) {
|
|
||||||
newReorderable.oldIndex = match.newIndex;
|
|
||||||
} else {
|
|
||||||
newReorderable.oldIndex = -1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.reorderables = reorderables;
|
|
||||||
|
|
||||||
if (shouldPropagateChanges) {
|
|
||||||
const movedReoRels: Array<Reorderable> = [];
|
|
||||||
let hasMetadataField = false;
|
|
||||||
this.reorderables.forEach((reorderable: Reorderable, index: number) => {
|
|
||||||
if (reorderable.hasMoved) {
|
|
||||||
if (reorderable instanceof ReorderableFormFieldMetadataValue) {
|
|
||||||
const prevIndex = reorderable.oldIndex;
|
|
||||||
hasMetadataField = true;
|
|
||||||
reorderable.update().pipe(take(1)).subscribe((v) => {
|
|
||||||
const reoMD = reorderable as ReorderableFormFieldMetadataValue;
|
|
||||||
reoMD.model.value = reoMD.metadataValue;
|
|
||||||
this.onChange({
|
|
||||||
$event: { previousIndex: prevIndex },
|
|
||||||
context: { index },
|
|
||||||
control: reoMD.control,
|
|
||||||
group: this.group,
|
|
||||||
model: reoMD.model,
|
|
||||||
type: DynamicFormControlEventType.Change
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else if (reorderable instanceof ReorderableRelationship) {
|
|
||||||
movedReoRels.push(reorderable)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isNotEmpty(movedReoRels) && hasMetadataField && hasValue(this.model.relationshipConfig)) {
|
|
||||||
// if it's a mix between entities and regular metadata fields,
|
|
||||||
// we need to save, since they use different endpoints and
|
|
||||||
// otherwise they'll get out of sync.
|
|
||||||
this.submissionService.dispatchSave(this.model.submissionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
observableCombineLatest(
|
|
||||||
movedReoRels.map((movedReoRel) => movedReoRel.update().pipe(take(1)))
|
|
||||||
).subscribe(() => {
|
|
||||||
this.changeDetectorRef.detectChanges();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
const prevIndex = event.previousIndex - 1;
|
||||||
|
const index = event.currentIndex - 1;
|
||||||
|
const $event = {
|
||||||
|
$event: { previousIndex: prevIndex },
|
||||||
|
context: { index },
|
||||||
|
control: (this.control as any).controls[index],
|
||||||
|
group: this.group,
|
||||||
|
model: this.model.groups[index].group[0],
|
||||||
|
type: DynamicFormControlEventType.Change
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onChange($event);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(index: number) {
|
update(event: any, index: number) {
|
||||||
if (index > 0) {
|
const $event = Object.assign({}, event, {
|
||||||
this.updateReorderables();
|
context: { index: index - 1}
|
||||||
}
|
});
|
||||||
|
|
||||||
|
console.log('$event', $event);
|
||||||
|
|
||||||
|
this.onChange($event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -366,14 +366,7 @@ export class SectionFormOperationsService {
|
|||||||
value, true);
|
value, true);
|
||||||
} else if (previousValue.isPathEqual(this.formBuilder.getPath(event.model)) || hasStoredValue) {
|
} else if (previousValue.isPathEqual(this.formBuilder.getPath(event.model)) || hasStoredValue) {
|
||||||
// Here model has a previous value changed or stored in the server
|
// Here model has a previous value changed or stored in the server
|
||||||
if (!value.hasValue()) {
|
if (hasValue(event.$event) && hasValue(event.$event.previousIndex)) {
|
||||||
// New value is empty, so dispatch a remove operation
|
|
||||||
if (this.getArrayIndexFromEvent(event) === 0) {
|
|
||||||
this.operationsBuilder.remove(pathCombiner.getPath(segmentedPath));
|
|
||||||
} else {
|
|
||||||
this.operationsBuilder.remove(pathCombiner.getPath(path));
|
|
||||||
}
|
|
||||||
} else if (hasValue(event.$event) && hasValue(event.$event.previousIndex)) {
|
|
||||||
if (event.$event.previousIndex < 0) {
|
if (event.$event.previousIndex < 0) {
|
||||||
this.operationsBuilder.add(
|
this.operationsBuilder.add(
|
||||||
pathCombiner.getPath(segmentedPath),
|
pathCombiner.getPath(segmentedPath),
|
||||||
@@ -384,6 +377,13 @@ export class SectionFormOperationsService {
|
|||||||
pathCombiner.getPath(segmentedPath + '/' + event.$event.previousIndex).path
|
pathCombiner.getPath(segmentedPath + '/' + event.$event.previousIndex).path
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else if (!value.hasValue()) {
|
||||||
|
// New value is empty, so dispatch a remove operation
|
||||||
|
if (this.getArrayIndexFromEvent(event) === 0) {
|
||||||
|
this.operationsBuilder.remove(pathCombiner.getPath(segmentedPath));
|
||||||
|
} else {
|
||||||
|
this.operationsBuilder.remove(pathCombiner.getPath(path));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// New value is not equal from the previous one, so dispatch a replace operation
|
// New value is not equal from the previous one, so dispatch a replace operation
|
||||||
this.operationsBuilder.replace(
|
this.operationsBuilder.replace(
|
||||||
|
Reference in New Issue
Block a user