diff --git a/src/app/+item-page/edit-item-page/item-metadata/edit-in-place-field/edit-in-place-field.component.html b/src/app/+item-page/edit-item-page/item-metadata/edit-in-place-field/edit-in-place-field.component.html index 80c78941c8..9f409d11bd 100644 --- a/src/app/+item-page/edit-item-page/item-metadata/edit-in-place-field/edit-in-place-field.component.html +++ b/src/app/+item-page/edit-item-page/item-metadata/edit-in-place-field/edit-in-place-field.component.html @@ -12,7 +12,6 @@ (dsClickOutside)="checkValidity(suggestionControl)" (findSuggestions)="findMetadataFieldSuggestions($event)" #suggestionControl="ngModel" - [dsInListValidator]="metadataFields" [valid]="(valid | async) !== false" dsAutoFocus autoFocusSelector=".suggestion_input" [ngModelOptions]="{standalone: true}" diff --git a/src/app/+item-page/edit-item-page/item-metadata/edit-in-place-field/edit-in-place-field.component.ts b/src/app/+item-page/edit-item-page/item-metadata/edit-in-place-field/edit-in-place-field.component.ts index cff1310f22..1bd4ebf341 100644 --- a/src/app/+item-page/edit-item-page/item-metadata/edit-in-place-field/edit-in-place-field.component.ts +++ b/src/app/+item-page/edit-item-page/item-metadata/edit-in-place-field/edit-in-place-field.component.ts @@ -37,11 +37,6 @@ export class EditInPlaceFieldComponent implements OnInit, OnChanges { */ @Input() url: string; - /** - * List of strings with all metadata field keys available - */ - @Input() metadataFields: string[]; - /** * The metadatum of this field */ @@ -65,7 +60,6 @@ export class EditInPlaceFieldComponent implements OnInit, OnChanges { constructor( private registryService: RegistryService, private objectUpdatesService: ObjectUpdatesService, - private metadataSchemaService: MetadataSchemaDataService ) { } diff --git a/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.html b/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.html index 366f6fffe2..042ed2d339 100644 --- a/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.html +++ b/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.html @@ -33,7 +33,6 @@ + [ngModelOptions]="{standalone: true}" autocomplete="off" + dsMetadataFieldValidator /> - \ No newline at end of file + diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 66bdea9217..bcdf8b2fd2 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -21,6 +21,7 @@ import { InfiniteScrollModule } from 'ngx-infinite-scroll'; import { EnumKeysPipe } from './utils/enum-keys-pipe'; import { FileSizePipe } from './utils/file-size-pipe'; +import { MetadataFieldValidator } from './utils/metadatafield-validator.directive'; import { SafeUrlPipe } from './utils/safe-url-pipe'; import { ConsolePipe } from './utils/console.pipe'; @@ -516,7 +517,8 @@ const DIRECTIVES = [ FileValueAccessorDirective, FileValidator, ClaimedTaskActionsDirective, - NgForTrackByIdDirective + NgForTrackByIdDirective, + MetadataFieldValidator ]; @NgModule({ diff --git a/src/app/shared/utils/metadatafield-validator.directive.ts b/src/app/shared/utils/metadatafield-validator.directive.ts new file mode 100644 index 0000000000..f4ee756fcb --- /dev/null +++ b/src/app/shared/utils/metadatafield-validator.directive.ts @@ -0,0 +1,66 @@ +import { Directive, Injectable } from '@angular/core'; +import { AbstractControl, AsyncValidator, NG_VALIDATORS, ValidationErrors } from '@angular/forms'; +import { map, switchMap, take } from 'rxjs/operators'; +import { of as observableOf, timer as observableTimer, Observable } from 'rxjs'; +import { MetadataFieldDataService } from '../../core/data/metadata-field-data.service'; +import { getSucceededRemoteData } from '../../core/shared/operators'; + +/** + * Directive for validating if a ngModel value is a valid metadata field + */ +@Directive({ + selector: '[ngModel][dsMetadataFieldValidator]', + // We add our directive to the list of existing validators + providers: [ + { provide: NG_VALIDATORS, useExisting: MetadataFieldValidator, multi: true } + ] +}) +@Injectable({ providedIn: 'root' }) +export class MetadataFieldValidator implements AsyncValidator { + + constructor(private metadataFieldService: MetadataFieldDataService) { + } + + /** + * The function that checks if the form control's value is currently valid + * @param control The FormControl + */ + validate(control: AbstractControl): Observable { + const resTimer = observableTimer(500).pipe( + switchMap(() => { + console.log('control', control) + if (!control.value) { + return observableOf({ invalidMetadataField: { value: control.value } }); + } + const mdFieldNameParts = control.value.split('.'); + if (mdFieldNameParts.length < 2) { + console.log('not enough parts') + return observableOf({ invalidMetadataField: { value: control.value } }); + } + + const res = this.metadataFieldService.findByFieldName(mdFieldNameParts[0], mdFieldNameParts[1], mdFieldNameParts.length == 3 ? mdFieldNameParts[2] : '', '') + .pipe( + getSucceededRemoteData(), + map((results) => { + console.log('results', results) + // TODO: - Currently it’s valid if the search returns at least one matching mdField; but this does mean that if for example a mdField named schema.elementEx.qualifierEx exists, but you fill in schema. or schema.elementEx then there is at least one result, but this doesn’t mean this is the whole of the field (the suggestion does show the options); alternatively it is valid if exact one matching field but then dc.title isn’t valid because the search schema=dc & element=title also returns for example dc.title.alternative + // - So the endpoint / restcontract should probably be changed to accommodate and exact search? Or was that already what was wanted and did I interpret it wrong? + if (results.payload.totalElements > 0) { + console.log('VALID') + return null; + } else { + console.log('NOT VALID') + return { invalidMetadataField: { value: control.value } }; + } + }) + ); + + res.pipe(take(1)).subscribe(); + + return res; + }) + ); + resTimer.pipe(take(1)).subscribe(); + return resTimer; + } +}