diff --git a/src/app/core/shared/browse-entry.model.ts b/src/app/core/shared/browse-entry.model.ts index 932c6946d1..0421ee1c3c 100644 --- a/src/app/core/shared/browse-entry.model.ts +++ b/src/app/core/shared/browse-entry.model.ts @@ -1,8 +1,8 @@ import { autoserialize, autoserializeAs } from 'cerialize'; -import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; - -export class BrowseEntry implements ListableObject { +import { Equatable } from '../utilities/equatable'; +import { hasValue } from '../../shared/empty.util'; +export class BrowseEntry implements Equatable { @autoserialize type: string; @@ -15,7 +15,15 @@ export class BrowseEntry implements ListableObject { @autoserializeAs('valueLang') language: string; + @excludeFromEquals @autoserialize count: number; + equals(other: BrowseEntry): boolean { + if (hasValue(other)) { + return false; + } + return false; + } + } diff --git a/src/app/core/utilities/equals.decorators.ts b/src/app/core/utilities/equals.decorators.ts new file mode 100644 index 0000000000..7088de5149 --- /dev/null +++ b/src/app/core/utilities/equals.decorators.ts @@ -0,0 +1,39 @@ +import { isEmpty } from '../../shared/empty.util'; + +const excludedFromEquals = new Map(); +const fieldsForEqualsMap = new Map(); + +export function excludeFromEquals(object: any, propertyName: string): any { + if (!object) { + return; + } + let list = excludedFromEquals.get(object.constructor); + if (isEmpty(list)) { + list = []; + } + excludedFromEquals.set(object.constructor, [...list, propertyName]); +} + +export function getExcludedFromEqualsFor(constructor: Function) { + return excludedFromEquals.get(constructor) || []; +} + +export function fieldsForEquals(...fields: string[]): any { + return function i(object: any, propertyName: string): any { + if (!object) { + return; + } + let fieldMap = fieldsForEqualsMap.get(object.constructor); + if (isEmpty(fieldMap)) { + fieldMap = new Map(); + } + fieldMap.set(propertyName, fields); + fieldsForEqualsMap.set(object.constructor, fieldMap); + } +} + + +export function getFieldsForEquals(constructor: Function, field: string) { + const fieldMap = excludedFromEquals.get(constructor) || new Map(); + return fieldMap.get(field); +} \ No newline at end of file diff --git a/src/app/core/utilities/equatable.ts b/src/app/core/utilities/equatable.ts new file mode 100644 index 0000000000..15dc680514 --- /dev/null +++ b/src/app/core/utilities/equatable.ts @@ -0,0 +1,33 @@ +import { getExcludedFromEqualsFor, getFieldsForEquals } from './equals.decorators'; +import { hasNoValue, hasValue } from '../../shared/empty.util'; + +function equalsByFields(object1, object2, fieldList): boolean { + const unequalProperty = fieldList.find((key) => { + if (object1[key] === object2[key]) { + return false; + } + if (hasNoValue(object1[key]) && hasNoValue(object2[key])) { + return false; + } + if (hasNoValue(object1[key]) || hasNoValue(object2[key])) { + return true; + } + const mapping = getFieldsForEquals(this.constructor, key); + if (hasValue(mapping)) { + return !equalsByFields(object1[key], object2[key], mapping); + } + if (this[key] instanceof EquatableObject) { + return !object1[key].equals(object2[key]); + } + return object1[key] !== object2[key]; + }); + return hasNoValue(unequalProperty); +} + +export abstract class EquatableObject { + equals(other: T): boolean { + const excludedKeys = getExcludedFromEqualsFor(this.constructor); + const keys = Object.keys(this).filter((key) => excludedKeys.findIndex((excludedKey) => key === excludedKey) < 0); + return equalsByFields(this, other, keys); + } +} \ No newline at end of file diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.html index 751bef7e54..85dcedd65e 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.html @@ -24,95 +24,6 @@ [selectable]="true" [selectionConfig]="{ repeatable: repeatable, listId: listId }"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.ts index 0f815e51fd..00f5b8e655 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.ts @@ -52,7 +52,7 @@ export class DsDynamicLookupRelationModalComponent implements OnInit { ngOnInit(): void { this.resetRoute(); this.onPaginationChange(this.initialPagination); - this.selectableListService.getSelectableList(this.listId).pipe(map((listState: SelectableListState) => hasValue(listState) && hasValue(listState.selection) ? listState.selection : [])); + this.selection = this.selectableListService.getSelectableList(this.listId).pipe(map((listState: SelectableListState) => hasValue(listState) && hasValue(listState.selection) ? listState.selection : [])); } search(query: string) { diff --git a/src/app/shared/object-collection/shared/listable-object.model.ts b/src/app/shared/object-collection/shared/listable-object.model.ts deleted file mode 100644 index 07c626cda2..0000000000 --- a/src/app/shared/object-collection/shared/listable-object.model.ts +++ /dev/null @@ -1 +0,0 @@ -export interface ListableObject {} diff --git a/src/app/shared/object-list/selectable-list/selectable-list.actions.ts b/src/app/shared/object-list/selectable-list/selectable-list.actions.ts index 0b757149b5..89f8682c33 100644 --- a/src/app/shared/object-list/selectable-list/selectable-list.actions.ts +++ b/src/app/shared/object-list/selectable-list/selectable-list.actions.ts @@ -68,7 +68,7 @@ export class SelectableListDeselectAction extends SelectableListAction { } export class SelectableListSetSelectionAction extends SelectableListAction { - payload: ListableObject; + payload: ListableObject[]; constructor(id: string, objects: ListableObject[]) { super(SelectableListActionTypes.SET_SELECTION, id); diff --git a/src/app/shared/object-list/selectable-list/selectable-list.reducer.ts b/src/app/shared/object-list/selectable-list/selectable-list.reducer.ts index ec4f57d752..80c6d594d2 100644 --- a/src/app/shared/object-list/selectable-list/selectable-list.reducer.ts +++ b/src/app/shared/object-list/selectable-list/selectable-list.reducer.ts @@ -71,7 +71,7 @@ function select(state: SelectableListState, action: SelectableListSelectAction) function selectSingle(state: SelectableListState, action: SelectableListSelectSingleAction) { let newSelection; - if (action.payload.multipleSelectionsAllowed && !isObjectInSelection(state.selection, action.payload)) { + if (action.payload.multipleSelectionsAllowed && !isObjectInSelection(state.selection, action.payload.object)) { newSelection = [...state.selection, action.payload.object]; } else { newSelection = [action.payload.object]; @@ -80,20 +80,19 @@ function selectSingle(state: SelectableListState, action: SelectableListSelectSi } function deselect(state: SelectableListState, action: SelectableListDeselectAction) { - const newSelection = state.selection.filter((selected) => hasNoValue(action.payload.find((object) => object === selected))); + const newSelection = state.selection.filter((selected) => hasNoValue(action.payload.find((object) => object.uuid === selected.uuid))); return Object.assign({}, state, { selection: newSelection }); } function deselectSingle(state: SelectableListState, action: SelectableListDeselectSingleAction) { const newSelection = state.selection.filter((selected) => { - return selected !== action.payload + return selected.uuid !== action.payload.uuid }); return Object.assign({}, state, { selection: newSelection }); } function setList(state: SelectableListState, action: SelectableListSetSelectionAction) { - const newSelection = [...state.selection, action.payload]; - return Object.assign({}, state, { selection: newSelection }); + return Object.assign({}, state, { selection: action.payload }); } function clearSelection(id: string) { @@ -102,5 +101,5 @@ function clearSelection(id: string) { function isObjectInSelection(selection: ListableObject[], object: ListableObject) { - return selection.findIndex((selected) => selected === object) >= 0 + return selection.findIndex((selected) => selected.uuid === object.uuid) >= 0 } diff --git a/src/app/shared/search/search-result.model.ts b/src/app/shared/search/search-result.model.ts index 57a44c8cc5..ee2f1231cb 100644 --- a/src/app/shared/search/search-result.model.ts +++ b/src/app/shared/search/search-result.model.ts @@ -16,4 +16,7 @@ export class SearchResult implements ListableObject { */ hitHighlights: MetadataMap; + get id(): string { + return this.indexableObject.id; + } }