diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-vocabulary.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-vocabulary.component.ts new file mode 100644 index 0000000000..bf09e237a5 --- /dev/null +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-vocabulary.component.ts @@ -0,0 +1,119 @@ +import { EventEmitter, Input, Output } from '@angular/core'; +import { FormGroup } from '@angular/forms'; + +import { + DynamicFormControlComponent, + DynamicFormLayoutService, + DynamicFormValidationService +} from '@ng-dynamic-forms/core'; +import { map } from 'rxjs/operators'; +import { Observable, of as observableOf } from 'rxjs'; + +import { VocabularyService } from '../../../../../core/submission/vocabularies/vocabulary.service'; +import { isNotEmpty } from '../../../../empty.util'; +import { FormFieldMetadataValueObject } from '../../models/form-field-metadata-value.model'; +import { VocabularyEntry } from '../../../../../core/submission/vocabularies/models/vocabulary-entry.model'; +import { DsDynamicInputModel } from './ds-dynamic-input.model'; +import { PageInfo } from '../../../../../core/shared/page-info.model'; + +/** + * An abstract class to be extended by form components that handle vocabulary + */ +export abstract class DsDynamicVocabularyComponent extends DynamicFormControlComponent { + + @Input() abstract bindId = true; + @Input() abstract group: FormGroup; + @Input() abstract model: DsDynamicInputModel; + + @Output() abstract blur: EventEmitter = new EventEmitter(); + @Output() abstract change: EventEmitter = new EventEmitter(); + @Output() abstract focus: EventEmitter = new EventEmitter(); + + public abstract pageInfo: PageInfo; + + constructor(protected vocabularyService: VocabularyService, + protected layoutService: DynamicFormLayoutService, + protected validationService: DynamicFormValidationService + ) { + super(layoutService, validationService); + } + + /** + * Sets the current value with the given value. + * @param value The value to set. + * @param init Representing if is init value or not. + */ + public abstract setCurrentValue(value: any, init?: boolean); + + /** + * Retrieves the init form value from model + */ + getInitValueFromModel(): Observable { + let initValue$: Observable; + if (isNotEmpty(this.model.value) && (this.model.value instanceof FormFieldMetadataValueObject)) { + let initEntry$: Observable; + if (this.model.value.hasAuthority()) { + initEntry$ = this.vocabularyService.getVocabularyEntryByID(this.model.value.authority, this.model.vocabularyOptions) + } else { + initEntry$ = this.vocabularyService.getVocabularyEntryByValue(this.model.value.value, this.model.vocabularyOptions) + } + initValue$ = initEntry$.pipe(map((initEntry: VocabularyEntry) => { + if (isNotEmpty(initEntry)) { + return new FormFieldMetadataValueObject( + initEntry.value, + null, + initEntry.authority, + initEntry.display + ); + } else { + return this.model.value as any; + } + })); + } else { + initValue$ = observableOf(new FormFieldMetadataValueObject(this.model.value)); + } + return initValue$; + } + + + /** + * Emits a blur event containing a given value. + * @param event The value to emit. + */ + onBlur(event: Event) { + this.blur.emit(event); + } + + /** + * Emits a focus event containing a given value. + * @param event The value to emit. + */ + onFocus(event) { + this.focus.emit(event); + } + + /** + * Emits a change event and updates model value. + * @param updateValue + */ + dispatchUpdate(updateValue: any) { + this.model.valueUpdates.next(updateValue); + this.change.emit(updateValue); + } + + /** + * Update the page info object + * @param elementsPerPage + * @param currentPage + * @param totalElements + * @param totalPages + */ + protected updatePageInfo(elementsPerPage: number, currentPage: number, totalElements?: number, totalPages?: number) { + this.pageInfo = Object.assign(new PageInfo(), { + elementsPerPage: elementsPerPage, + currentPage: currentPage, + totalElements: totalElements, + totalPages: totalPages + }); + } +} diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts index 3c5a86f362..d7c492ccde 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts @@ -9,7 +9,6 @@ import { } from '@ng-dynamic-forms/core'; import { findKey } from 'lodash'; -import { VocabularyFindOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-find-options.model'; import { hasValue, isNotEmpty } from '../../../../../empty.util'; import { DynamicListCheckboxGroupModel } from './dynamic-list-checkbox-group.model'; import { FormBuilderService } from '../../../form-builder.service'; @@ -18,6 +17,7 @@ import { VocabularyService } from '../../../../../../core/submission/vocabularie import { getFirstSucceededRemoteDataPayload } from '../../../../../../core/shared/operators'; import { PaginatedList } from '../../../../../../core/data/paginated-list'; import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model'; +import { PageInfo } from '../../../../../../core/shared/page-info.model'; export interface ListItem { id: string, @@ -26,12 +26,14 @@ export interface ListItem { index: number } +/** + * Component representing a list input field + */ @Component({ selector: 'ds-dynamic-list', styleUrls: ['./dynamic-list.component.scss'], templateUrl: './dynamic-list.component.html' }) - export class DsDynamicListComponent extends DynamicFormControlComponent implements OnInit { @Input() bindId = true; @Input() group: FormGroup; @@ -43,7 +45,6 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen public items: ListItem[][] = []; protected optionsList: VocabularyEntry[]; - protected searchOptions: VocabularyFindOptions; constructor(private vocabularyService: VocabularyService, private cdr: ChangeDetectorRef, @@ -56,14 +57,6 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen ngOnInit() { if (this.hasAuthorityOptions()) { - // TODO Replace max elements 1000 with a paginated request when pagination bug is resolved - this.searchOptions = new VocabularyFindOptions( - this.model.vocabularyOptions.scope, - this.model.vocabularyOptions.name, - this.model.vocabularyOptions.metadata, - '', - 1000, // Max elements - 1);// Current Page this.setOptionsFromAuthority(); } } @@ -99,7 +92,10 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen protected setOptionsFromAuthority() { if (this.model.vocabularyOptions.name && this.model.vocabularyOptions.name.length > 0) { const listGroup = this.group.controls[this.model.id] as FormGroup; - this.vocabularyService.getVocabularyEntries(this.searchOptions).pipe( + const pageInfo: PageInfo = new PageInfo({ + elementsPerPage: Number.MAX_VALUE, currentPage: 1 + } as PageInfo); + this.vocabularyService.getVocabularyEntries(this.model.vocabularyOptions, pageInfo).pipe( getFirstSucceededRemoteDataPayload() ).subscribe((entries: PaginatedList) => { let groupCounter = 0; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.html index 254b15411d..b274197f13 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.html @@ -21,8 +21,8 @@ [placeholder]="model.placeholder | translate" [readonly]="model.readOnly" (change)="onChange($event)" - (blur)="onBlurEvent($event); $event.stopPropagation(); sdRef.close();" - (focus)="onFocusEvent($event); $event.stopPropagation(); sdRef.close();" + (blur)="onBlur($event); $event.stopPropagation(); sdRef.close();" + (focus)="onFocus($event); $event.stopPropagation(); sdRef.close();" (click)="$event.stopPropagation(); $event.stopPropagation(); sdRef.close();"> @@ -40,8 +40,8 @@ [placeholder]="model.secondPlaceholder | translate" [readonly]="model.readOnly" (change)="onChange($event)" - (blur)="onBlurEvent($event); $event.stopPropagation(); sdRef.close();" - (focus)="onFocusEvent($event); $event.stopPropagation(); sdRef.close();" + (blur)="onBlur($event); $event.stopPropagation(); sdRef.close();" + (focus)="onFocus($event); $event.stopPropagation(); sdRef.close();" (click)="$event.stopPropagation(); sdRef.close();">
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts index ce45e113a0..66eca2393b 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts @@ -4,6 +4,7 @@ import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angul import { async, ComponentFixture, fakeAsync, inject, TestBed, tick, } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; +import { of as observableOf } from 'rxjs'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { TranslateModule } from '@ngx-translate/core'; import { InfiniteScrollModule } from 'ngx-infinite-scroll'; @@ -309,7 +310,13 @@ describe('Dynamic Lookup component', () => { lookupComp = lookupFixture.componentInstance; // FormComponent test instance lookupComp.group = LOOKUP_TEST_GROUP; lookupComp.model = new DynamicLookupModel(LOOKUP_TEST_MODEL_CONFIG); - lookupComp.model.value = new FormFieldMetadataValueObject('test', null, 'test001'); + const entry = observableOf(Object.assign(new VocabularyEntry(), { + authority: null, + value: 'test', + display: 'testDisplay' + })); + spyOn((lookupComp as any).vocabularyService, 'getVocabularyEntryByValue').and.returnValue(entry); + (lookupComp.model as any).value = new FormFieldMetadataValueObject('test', null, null, 'testDisplay'); lookupFixture.detectChanges(); // spyOn(store, 'dispatch'); @@ -318,9 +325,52 @@ describe('Dynamic Lookup component', () => { lookupFixture.destroy(); lookupComp = null; }); - it('should init component properly', () => { - expect(lookupComp.firstInputValue).toBe('test'); + it('should init component properly', fakeAsync(() => { + tick(); + expect(lookupComp.firstInputValue).toBe('testDisplay'); + expect((lookupComp as any).vocabularyService.getVocabularyEntryByValue).toHaveBeenCalled(); + })); + + it('should have search button disabled on edit mode', () => { + lookupComp.editMode = true; + lookupFixture.detectChanges(); + + const de = lookupFixture.debugElement.queryAll(By.css('button')); + const searchBtnEl = de[0].nativeElement; + const saveBtnEl = de[1].nativeElement; + expect(searchBtnEl.disabled).toBe(true); + expect(saveBtnEl.disabled).toBe(false); + expect(saveBtnEl.textContent.trim()).toBe('form.save'); + }); + }); + describe('and init model value is not empty with authority', () => { + beforeEach(() => { + + lookupFixture = TestBed.createComponent(DsDynamicLookupComponent); + lookupComp = lookupFixture.componentInstance; // FormComponent test instance + lookupComp.group = LOOKUP_TEST_GROUP; + lookupComp.model = new DynamicLookupModel(LOOKUP_TEST_MODEL_CONFIG); + const entry = observableOf(Object.assign(new VocabularyEntry(), { + authority: 'test001', + value: 'test', + display: 'testDisplay' + })); + spyOn((lookupComp as any).vocabularyService, 'getVocabularyEntryByID').and.returnValue(entry); + lookupComp.model.value = new FormFieldMetadataValueObject('test', null, 'test001', 'testDisplay'); + lookupFixture.detectChanges(); + + // spyOn(store, 'dispatch'); + }); + afterEach(() => { + lookupFixture.destroy(); + lookupComp = null; + }); + it('should init component properly', fakeAsync(() => { + tick(); + expect(lookupComp.firstInputValue).toBe('testDisplay'); + expect((lookupComp as any).vocabularyService.getVocabularyEntryByID).toHaveBeenCalled(); + })); it('should have search button disabled on edit mode', () => { lookupComp.editMode = true; @@ -430,6 +480,13 @@ describe('Dynamic Lookup component', () => { lookupComp.group = LOOKUP_TEST_GROUP; lookupComp.model = new DynamicLookupNameModel(LOOKUP_NAME_TEST_MODEL_CONFIG); lookupComp.model.value = new FormFieldMetadataValueObject('Name, Lastname', null, 'test001'); + const entry = observableOf(Object.assign(new VocabularyEntry(), { + authority: null, + value: 'Name, Lastname', + display: 'Name, Lastname' + })); + spyOn((lookupComp as any).vocabularyService, 'getVocabularyEntryByValue').and.returnValue(entry); + (lookupComp.model as any).value = new FormFieldMetadataValueObject('Name, Lastname', null, null, 'Name, Lastname'); lookupFixture.detectChanges(); }); @@ -437,10 +494,55 @@ describe('Dynamic Lookup component', () => { lookupFixture.destroy(); lookupComp = null; }); - it('should init component properly', () => { + it('should init component properly', fakeAsync(() => { + tick(); expect(lookupComp.firstInputValue).toBe('Name'); expect(lookupComp.secondInputValue).toBe('Lastname'); + expect((lookupComp as any).vocabularyService.getVocabularyEntryByValue).toHaveBeenCalled(); + })); + + it('should have search button disabled on edit mode', () => { + lookupComp.editMode = true; + lookupFixture.detectChanges(); + + const de = lookupFixture.debugElement.queryAll(By.css('button')); + const searchBtnEl = de[0].nativeElement; + const saveBtnEl = de[1].nativeElement; + expect(searchBtnEl.disabled).toBe(true); + expect(saveBtnEl.disabled).toBe(false); + expect(saveBtnEl.textContent.trim()).toBe('form.save'); + }); + }); + + describe('and init model value is not empty with authority', () => { + beforeEach(() => { + + lookupFixture = TestBed.createComponent(DsDynamicLookupComponent); + lookupComp = lookupFixture.componentInstance; // FormComponent test instance + lookupComp.group = LOOKUP_TEST_GROUP; + lookupComp.model = new DynamicLookupNameModel(LOOKUP_NAME_TEST_MODEL_CONFIG); + lookupComp.model.value = new FormFieldMetadataValueObject('Name, Lastname', null, 'test001'); + const entry = observableOf(Object.assign(new VocabularyEntry(), { + authority: 'test001', + value: 'Name, Lastname', + display: 'Name, Lastname' + })); + spyOn((lookupComp as any).vocabularyService, 'getVocabularyEntryByID').and.returnValue(entry); + lookupComp.model.value = new FormFieldMetadataValueObject('Name, Lastname', null, 'test001', 'Name, Lastname'); + lookupFixture.detectChanges(); + + }); + afterEach(() => { + lookupFixture.destroy(); + lookupComp = null; + }); + it('should init component properly', fakeAsync(() => { + tick(); + expect(lookupComp.firstInputValue).toBe('Name'); + expect(lookupComp.secondInputValue).toBe('Lastname'); + expect((lookupComp as any).vocabularyService.getVocabularyEntryByID).toHaveBeenCalled(); + })); it('should have search button disabled on edit mode', () => { lookupComp.editMode = true; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.ts index 24422e891a..9ae4ad0737 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.ts @@ -4,15 +4,10 @@ import { FormGroup } from '@angular/forms'; import { of as observableOf, Subscription } from 'rxjs'; import { catchError, distinctUntilChanged } from 'rxjs/operators'; import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'; -import { - DynamicFormControlComponent, - DynamicFormLayoutService, - DynamicFormValidationService -} from '@ng-dynamic-forms/core'; +import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core'; import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service'; -import { VocabularyFindOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-find-options.model'; -import { hasValue, isEmpty, isNotEmpty, isNull, isUndefined } from '../../../../../empty.util'; +import { hasValue, isEmpty, isNotEmpty } from '../../../../../empty.util'; import { PageInfo } from '../../../../../../core/shared/page-info.model'; import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model'; import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model'; @@ -20,16 +15,21 @@ import { DynamicLookupNameModel } from './dynamic-lookup-name.model'; import { ConfidenceType } from '../../../../../../core/shared/confidence-type'; import { PaginatedList } from '../../../../../../core/data/paginated-list'; import { getFirstSucceededRemoteDataPayload } from '../../../../../../core/shared/operators'; +import { DsDynamicVocabularyComponent } from '../dynamic-vocabulary.component'; +import { DynamicLookupModel } from './dynamic-lookup.model'; +/** + * Component representing a lookup or lookup-name input field + */ @Component({ selector: 'ds-dynamic-lookup', styleUrls: ['./dynamic-lookup.component.scss'], templateUrl: './dynamic-lookup.component.html' }) -export class DsDynamicLookupComponent extends DynamicFormControlComponent implements OnDestroy, OnInit { +export class DsDynamicLookupComponent extends DsDynamicVocabularyComponent implements OnDestroy, OnInit { @Input() bindId = true; @Input() group: FormGroup; - @Input() model: any; + @Input() model: DynamicLookupModel | DynamicLookupNameModel; @Output() blur: EventEmitter = new EventEmitter(); @Output() change: EventEmitter = new EventEmitter(); @@ -42,89 +42,97 @@ export class DsDynamicLookupComponent extends DynamicFormControlComponent implem public pageInfo: PageInfo; public optionsList: any; - protected searchOptions: VocabularyFindOptions; protected subs: Subscription[] = []; - constructor(private vocabularyService: VocabularyService, + constructor(protected vocabularyService: VocabularyService, private cdr: ChangeDetectorRef, protected layoutService: DynamicFormLayoutService, protected validationService: DynamicFormValidationService ) { - super(layoutService, validationService); + super(vocabularyService, layoutService, validationService); } + /** + * Converts an item from the result list to a `string` to display in the `` field. + */ inputFormatter = (x: { display: string }, y: number) => { return y === 1 ? this.firstInputValue : this.secondInputValue; }; + /** + * Initialize the component, setting up the init form value + */ ngOnInit() { - this.searchOptions = new VocabularyFindOptions( - this.model.vocabularyOptions.scope, - this.model.vocabularyOptions.name, - this.model.vocabularyOptions.metadata, - '', - this.model.maxOptions, - 1); - - this.setInputsValue(this.model.value); + if (isNotEmpty(this.model.value)) { + this.setCurrentValue(this.model.value, true); + } this.subs.push(this.model.valueUpdates .subscribe((value) => { if (isEmpty(value)) { this.resetFields(); } else if (!this.editMode) { - this.setInputsValue(this.model.value); + this.setCurrentValue(this.model.value); } })); } - public formatItemForInput(item: any, field: number): string { - if (isUndefined(item) || isNull(item)) { - return ''; - } - return (typeof item === 'string') ? item : this.inputFormatter(item, field); - } - + /** + * Check if model value has an authority + */ public hasAuthorityValue() { return hasValue(this.model.value) && this.model.value.hasAuthority(); } + /** + * Check if current value has an authority + */ public hasEmptyValue() { return isNotEmpty(this.getCurrentValue()); } + /** + * Clear inputs whether there is no results and authority is closed + */ public clearFields() { - // Clear inputs whether there is no results and authority is closed if (this.model.vocabularyOptions.closed) { this.resetFields(); } } + /** + * Check if edit button is disabled + */ public isEditDisabled() { return !this.hasAuthorityValue(); } + /** + * Check if input is disabled + */ public isInputDisabled() { return (this.model.vocabularyOptions.closed && this.hasAuthorityValue() && !this.editMode); } + /** + * Check if model is instanceof DynamicLookupNameModel + */ public isLookupName() { return (this.model instanceof DynamicLookupNameModel); } + /** + * Check if search button is disabled + */ public isSearchDisabled() { return isEmpty(this.firstInputValue) || this.editMode; } - public onBlurEvent(event: Event) { - this.blur.emit(event); - } - - public onFocusEvent(event) { - this.focus.emit(event); - } - + /** + * Update model value with the typed text if vocabulary is not closed + * @param event the typed text + */ public onChange(event) { event.preventDefault(); if (!this.model.vocabularyOptions.closed) { @@ -139,31 +147,51 @@ export class DsDynamicLookupComponent extends DynamicFormControlComponent implem } } + /** + * Load more result entries + */ public onScroll() { if (!this.loading && this.pageInfo.currentPage <= this.pageInfo.totalPages) { - this.searchOptions.currentPage++; + this.updatePageInfo( + this.pageInfo.elementsPerPage, + this.pageInfo.currentPage + 1, + this.pageInfo.totalElements, + this.pageInfo.totalPages + ); this.search(); } } + /** + * Update model value with selected entry + * @param event the selected entry + */ public onSelect(event) { this.updateModel(event); } + /** + * Reset the current value when dropdown toggle + */ public openChange(isOpened: boolean) { if (!isOpened) { if (this.model.vocabularyOptions.closed && !this.hasAuthorityValue()) { - this.setInputsValue(''); + this.setCurrentValue(''); } } } + /** + * Reset the model value + */ public remove() { this.group.markAsPristine(); - this.model.valueUpdates.next(null); - this.change.emit(null); + this.dispatchUpdate(null) } + /** + * Saves all changes + */ public saveChanges() { if (isNotEmpty(this.getCurrentValue())) { const newValue = Object.assign(new VocabularyEntry(), this.model.value, { @@ -177,15 +205,21 @@ export class DsDynamicLookupComponent extends DynamicFormControlComponent implem this.switchEditMode(); } + /** + * Converts a stream of text values from the `` element to the stream of the array of items + * to display in the result list. + */ public search() { this.optionsList = null; - this.pageInfo = null; - - // Query - this.searchOptions.query = this.getCurrentValue(); - + this.updatePageInfo(this.model.maxOptions, 1); this.loading = true; - this.subs.push(this.vocabularyService.getVocabularyEntries(this.searchOptions).pipe( + + this.subs.push(this.vocabularyService.getVocabularyEntriesByValue( + this.getCurrentValue(), + false, + this.model.vocabularyOptions, + this.pageInfo + ).pipe( getFirstSucceededRemoteDataPayload(), catchError(() => observableOf(new PaginatedList( @@ -195,18 +229,28 @@ export class DsDynamicLookupComponent extends DynamicFormControlComponent implem ), distinctUntilChanged()) .subscribe((list: PaginatedList) => { - console.log(list); this.optionsList = list.page; - this.pageInfo = list.pageInfo; + this.updatePageInfo( + list.pageInfo.elementsPerPage, + list.pageInfo.currentPage, + list.pageInfo.totalElements, + list.pageInfo.totalPages + ); this.loading = false; this.cdr.detectChanges(); })); } + /** + * Changes the edit mode flag + */ public switchEditMode() { this.editMode = !this.editMode; } + /** + * Callback functions for whenClickOnConfidenceNotAccepted event + */ public whenClickOnConfidenceNotAccepted(sdRef: NgbDropdown, confidence: ConfidenceType) { if (!this.model.readOnly) { sdRef.open(); @@ -220,6 +264,38 @@ export class DsDynamicLookupComponent extends DynamicFormControlComponent implem .forEach((sub) => sub.unsubscribe()); } + /** + * Sets the current value with the given value. + * @param value The value to set. + * @param init Representing if is init value or not. + */ + public setCurrentValue(value: any, init = false) { + if (init) { + this.getInitValueFromModel() + .subscribe((value: FormFieldMetadataValueObject) => this.setDisplayInputValue(value.display)); + } else if (hasValue(value)) { + if (value instanceof FormFieldMetadataValueObject || value instanceof VocabularyEntry) { + this.setDisplayInputValue(value.display); + } + } + } + + protected setDisplayInputValue(displayValue: string) { + if (hasValue(displayValue)) { + if (this.isLookupName()) { + const values = displayValue.split((this.model as DynamicLookupNameModel).separator); + + this.firstInputValue = (values[0] || '').trim(); + this.secondInputValue = (values[1] || '').trim(); + } else { + this.firstInputValue = displayValue || ''; + } + } + } + + /** + * Gets the current text present in the input field(s) + */ protected getCurrentValue(): string { let result = ''; if (!this.isLookupName()) { @@ -237,6 +313,9 @@ export class DsDynamicLookupComponent extends DynamicFormControlComponent implem return result; } + /** + * Clear text present in the input field(s) + */ protected resetFields() { this.firstInputValue = ''; if (this.isLookupName()) { @@ -244,32 +323,12 @@ export class DsDynamicLookupComponent extends DynamicFormControlComponent implem } } - protected setInputsValue(value) { - if (hasValue(value)) { - let displayValue = value; - if (value instanceof FormFieldMetadataValueObject || value instanceof VocabularyEntry) { - displayValue = value.display; - } - - if (hasValue(displayValue)) { - if (this.isLookupName()) { - const values = displayValue.split((this.model as DynamicLookupNameModel).separator); - - this.firstInputValue = (values[0] || '').trim(); - this.secondInputValue = (values[1] || '').trim(); - } else { - this.firstInputValue = displayValue || ''; - } - } - } - } - protected updateModel(value) { this.group.markAsDirty(); - this.model.valueUpdates.next(value); - this.setInputsValue(value); - this.change.emit(value); + this.dispatchUpdate(value); + this.setCurrentValue(value); this.optionsList = null; this.pageInfo = null; } + } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts index 21606d7abc..51cf69d560 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts @@ -23,13 +23,15 @@ import { hasValue, isEmpty, isNotEmpty, isNotNull } from '../../../../../empty.u import { shrinkInOut } from '../../../../../animations/shrink'; import { ChipsItem } from '../../../../../chips/models/chips-item.model'; import { hasOnlyEmptyProperties } from '../../../../../object.util'; -import { VocabularyFindOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-find-options.model'; import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service'; import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model'; import { environment } from '../../../../../../../environments/environment'; import { getFirstSucceededRemoteDataPayload } from '../../../../../../core/shared/operators'; import { VocabularyEntryDetail } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry-detail.model'; +/** + * Component representing a group input field + */ @Component({ selector: 'ds-dynamic-relation-group', styleUrls: ['./dynamic-relation-group.component.scss'], diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html index cfe50def98..7a35287a99 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html @@ -1,5 +1,5 @@ -
- + -