use reorderables instead of relationships

This commit is contained in:
Art Lowel
2019-12-02 18:30:35 +01:00
parent bc8e7d8fe6
commit 78d1c5ee2b
5 changed files with 119 additions and 88 deletions

View File

@@ -1,4 +1,4 @@
import { Component } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { metadataRepresentationComponent } from '../../../../shared/metadata-representation/metadata-representation.decorator';
import { MetadataRepresentationType } from '../../../../core/shared/metadata-representation/metadata-representation.model';
import { ItemMetadataRepresentationListElementComponent } from '../../../../shared/object-list/metadata-representation-list-element/item/item-metadata-representation-list-element.component';
@@ -11,5 +11,8 @@ import { ItemMetadataRepresentationListElementComponent } from '../../../../shar
/**
* The component for displaying an item of the type Person as a metadata field
*/
export class PersonItemMetadataListElementComponent extends ItemMetadataRepresentationListElementComponent {
export class PersonItemMetadataListElementComponent extends ItemMetadataRepresentationListElementComponent implements OnInit {
ngOnInit(): void {
console.log('this.metadataRepresentation', this.metadataRepresentation);
}
}

View File

@@ -54,8 +54,8 @@
<div *ngIf="hasRelationLookup" class="mt-3">
<ul class="list-unstyled" cdkDropList (cdkDropListDropped)="moveSelection($event)">
<ds-existing-metadata-list-element cdkDrag [cdkDragData]="relationship" *ngFor="let relationship of relationships; trackBy: trackRelationship"
[relationship]="relationship"
<ds-existing-metadata-list-element cdkDrag [cdkDragData]="relationship" *ngFor="let reorderable of reorderables; trackBy: trackReorderable"
[reoRel]="reorderable"
[submissionItem]="item"
[listId]="listId"
[metadataFields]="model.metadataFields"

View File

@@ -50,6 +50,10 @@ import {
DynamicNGBootstrapTimePickerComponent
} from '@ng-dynamic-forms/ui-ng-bootstrap';
import { TranslateService } from '@ngx-translate/core';
import {
Reorderable,
ReorderableRelationship
} from './existing-metadata-list-element/existing-metadata-list-element.component';
import { DYNAMIC_FORM_CONTROL_TYPE_TYPEAHEAD } from './models/typeahead/dynamic-typeahead.model';
import { DYNAMIC_FORM_CONTROL_TYPE_SCROLLABLE_DROPDOWN } from './models/scrollable-dropdown/dynamic-scrollable-dropdown.model';
@@ -176,15 +180,14 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
@Input() hasErrorMessaging = false;
@Input() layout = null as DynamicFormLayout;
@Input() model: any;
relationships$: Observable<Relationship[]>;
relationships: Relationship[];
reorderables$: Observable<ReorderableRelationship[]>;
reorderables: ReorderableRelationship[];
hasRelationLookup: boolean;
modalRef: NgbModalRef;
item: Item;
listId: string;
searchConfig: string;
/**
* List of subscriptions to unsubscribe from
*/
@@ -223,6 +226,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
ngOnInit(): void {
this.hasRelationLookup = hasValue(this.model.relationship);
this.reorderables = [];
if (this.hasRelationLookup) {
this.listId = 'list-' + this.model.relationship.relationshipType;
const item$ = this.submissionObjectService
@@ -238,7 +242,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
);
this.subs.push(item$.subscribe((item) => this.item = item));
this.relationships$ = item$.pipe(
this.reorderables$ = item$.pipe(
switchMap((item) => this.relationService.getItemRelationshipsByLabel(item, this.model.relationship.relationshipType)
.pipe(
getAllSucceededRemoteData(),
@@ -251,28 +255,24 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
relationship.leftItem.pipe(
getSucceededRemoteData(),
getRemoteDataPayload(),
map((item: Item) => {
return { relationship, left: item.uuid === this.item.uuid }
map((leftItem: Item) => {
return new ReorderableRelationship(relationship, leftItem.uuid !== this.item.uuid)
}),
)
))),
map((relationships: { relationship: Relationship, left: boolean }[]) =>
map((relationships: ReorderableRelationship[]) =>
relationships
.sort((
a: { relationship: Relationship, left: boolean },
b: { relationship: Relationship, left: boolean }
) => {
const placeA: number = a.left ? a.relationship.leftPlace : a.relationship.rightPlace;
const placeB: number = b.left ? b.relationship.leftPlace : b.relationship.rightPlace;
return Math.sign(placeA - placeB);
.sort((a: Reorderable, b: Reorderable) => {
return Math.sign(a.getPlace() - b.getPlace());
})
.map((relationship) => relationship.relationship)
)
)
)
);
this.relationships$.subscribe((rels) => this.relationships = rels);
this.subs.push(this.reorderables$.subscribe((rs) => {
this.reorderables = rs
}));
this.relationService.getRelatedItemsByLabel(this.item, this.model.relationship.relationshipType).pipe(
map((items: RemoteData<PaginatedList<Item>>) => items.payload.page.map((item) => Object.assign(new ItemSearchResult(), { indexableObject: item }))),
@@ -334,27 +334,18 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
modalComp.item = this.item;
}
moveSelection(event: CdkDragDrop<Relationship>) {
moveItemInArray(this.relationships, event.previousIndex, event.currentIndex);
moveItemInArray(this.reorderables, event.previousIndex, event.currentIndex);
this.zone.runOutsideAngular(() => {
observableCombineLatest(
this.relationships.map((relationship: Relationship, index: number) =>
relationship.leftItem.pipe(
getSucceededRemoteData(),
getRemoteDataPayload(),
map((item: Item) => {
const left: boolean = item.uuid === this.item.uuid;
if (left) {
return { relationship, left: item.uuid === this.item.uuid, oldIndex: relationship.leftPlace, newIndex: index }
} else {
return { relationship, left: item.uuid === this.item.uuid, oldIndex: relationship.rightPlace, newIndex: index }
this.reorderables.map((reo: Reorderable, index: number) => {
reo.oldIndex = reo.getPlace();
reo.newIndex = index;
return reo;
}
}),
)
)
).pipe(
switchMap((relationships: { relationship: Relationship, left: boolean, oldIndex: number, newIndex: number }[]) =>
switchMap((relationships: Array<{ relationship: Relationship, left: boolean, oldIndex: number, newIndex: number }>) =>
observableCombineLatest(relationships.map((rel: { relationship: Relationship, left: boolean, oldIndex: number, newIndex: number }) => {
if (rel.oldIndex !== rel.newIndex) {
return this.relationshipService.updatePlace(rel.relationship, rel.newIndex, rel.left);
@@ -381,7 +372,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
/**
* Prevent unnecessary rerendering so fields don't lose focus
*/
trackRelationship(index, relationship: Relationship) {
return hasValue(relationship) ? relationship.id : undefined;
trackReorderable(index, reorderable: Reorderable) {
return hasValue(reorderable) ? reorderable.getId() : undefined;
}
}

View File

@@ -1,4 +1,4 @@
<li *ngIf="metadataRepresentation$ | async">
<li *ngIf="metadataRepresentation">
<button type="button" class="close float-left" aria-label="Move button" cdkDragHandle>
<i aria-hidden="true" class="fas fa-arrows-alt fa-xs"></i>
</button>
@@ -6,6 +6,6 @@
<span aria-hidden="true">&times;</span>
</button>
<span class="d-inline-block align-middle ml-1">
<ds-metadata-representation-loader [mdRepresentation]="metadataRepresentation$ | async"></ds-metadata-representation-loader>
<ds-metadata-representation-loader [mdRepresentation]="metadataRepresentation"></ds-metadata-representation-loader>
</span>
</li>

View File

@@ -1,10 +1,16 @@
import { Component, Input, OnChanges, OnInit } from '@angular/core';
import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core';
import { Item } from '../../../../../core/shared/item.model';
import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../../core/shared/operators';
import { MetadataRepresentation } from '../../../../../core/shared/metadata-representation/metadata-representation.model';
import {
getAllSucceededRemoteData,
getRemoteDataPayload,
getSucceededRemoteData
} from '../../../../../core/shared/operators';
import { hasValue, isNotEmpty } from '../../../../empty.util';
import { filter, map, take } from 'rxjs/operators';
import { of as observableOf, Subscription } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { Relationship } from '../../../../../core/shared/item-relationships/relationship.model';
import { combineLatest as observableCombineLatest } from 'rxjs';
import { combineLatest as observableCombineLatest, of } from 'rxjs';
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';
@@ -14,19 +20,55 @@ import { Store } from '@ngrx/store';
import { AppState } from '../../../../../app.reducer';
import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model';
export abstract class Reorderable {
constructor(public oldIndex?: number, public newIndex?: number) {
}
abstract getId(): string;
abstract getPlace(): number;
}
export class ReorderableRelationship extends Reorderable {
relationship: Relationship;
useLeftItem: boolean;
constructor(relationship: Relationship, useLeftItem: boolean, oldIndex?: number, newIndex?: number) {
super(oldIndex, newIndex);
this.relationship = relationship;
this.useLeftItem = useLeftItem;
}
getId(): string {
return this.relationship.id;
}
getPlace(): number {
if (this.useLeftItem) {
return this.relationship.rightPlace
} else {
return this.relationship.leftPlace
}
}
}
@Component({
selector: 'ds-existing-metadata-list-element',
templateUrl: './existing-metadata-list-element.component.html',
styleUrls: ['./existing-metadata-list-element.component.scss']
})
export class ExistingMetadataListElementComponent implements OnChanges {
export class ExistingMetadataListElementComponent implements OnInit, OnChanges, OnDestroy {
@Input() listId: string;
@Input() submissionItem: Item;
@Input() relationship: Relationship;
@Input() reoRel: ReorderableRelationship;
@Input() metadataFields: string[];
@Input() relationshipOptions: RelationshipOptions;
metadataRepresentation$;
relatedItem$;
metadataRepresentation: MetadataRepresentation;
relatedItem: Item;
/**
* List of subscriptions to unsubscribe from
*/
private subs: Subscription[] = [];
constructor(
private selectableListService: SelectableListService,
@@ -34,49 +76,44 @@ export class ExistingMetadataListElementComponent implements OnChanges {
) {
}
ngOnInit(): void {
console.log('reoRel', this.reoRel);
}
ngOnChanges() {
const leftItem$ = this.relationship.leftItem.pipe(
getSucceededRemoteData(),
const item$ = this.reoRel.useLeftItem ?
this.reoRel.relationship.leftItem : this.reoRel.relationship.rightItem;
this.subs.push(item$.pipe(
getAllSucceededRemoteData(),
getRemoteDataPayload(),
filter((item: Item) => hasValue(item) && isNotEmpty(item.uuid))
);
).subscribe((item: Item) => {
this.relatedItem = item;
const rightItem$ = this.relationship.rightItem.pipe(
getSucceededRemoteData(),
getRemoteDataPayload(),
filter((item: Item) => hasValue(item) && isNotEmpty(item.uuid))
);
this.relatedItem$ = observableCombineLatest(
leftItem$,
rightItem$,
).pipe(
map((items: Item[]) =>
items.find((item) => item.uuid !== this.submissionItem.uuid)
)
);
this.metadataRepresentation$ = this.relatedItem$.pipe(
map((relatedItem: Item) => {
console.log(relatedItem);
const relationMD: MetadataValue = this.submissionItem.firstMetadata(this.relationshipOptions.metadataField, { value: relatedItem.uuid });
console.log(relationMD);
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 });
return Object.assign(
this.metadataRepresentation = Object.assign(
new ItemMetadataRepresentation(metadataRepresentationMD),
relatedItem
this.relatedItem
)
}
}
)
);
}));
}
removeSelection() {
this.relatedItem$.pipe(take(1)).subscribe((relatedItem: Item) => {
this.selectableListService.deselectSingle(this.listId, Object.assign(new ItemSearchResult(), { indexableObject: relatedItem }));
this.store.dispatch(new RemoveRelationshipAction(this.submissionItem, relatedItem, this.relationshipOptions.relationshipType))
})
this.selectableListService.deselectSingle(this.listId, Object.assign(new ItemSearchResult(), { indexableObject: this.relatedItem }));
this.store.dispatch(new RemoveRelationshipAction(this.submissionItem, this.relatedItem, this.relationshipOptions.relationshipType))
}
/**
* Unsubscribe from all subscriptions
*/
ngOnDestroy(): void {
this.subs
.filter((sub) => hasValue(sub))
.forEach((sub) => sub.unsubscribe());
}
}