mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
[CST-3088] Created abstract form component to handle vocabularies
This commit is contained in:
@@ -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<any> = new EventEmitter<any>();
|
||||
@Output() abstract change: EventEmitter<any> = new EventEmitter<any>();
|
||||
@Output() abstract focus: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
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<FormFieldMetadataValueObject> {
|
||||
let initValue$: Observable<FormFieldMetadataValueObject>;
|
||||
if (isNotEmpty(this.model.value) && (this.model.value instanceof FormFieldMetadataValueObject)) {
|
||||
let initEntry$: Observable<VocabularyEntry>;
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
@@ -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<VocabularyEntry>) => {
|
||||
let groupCounter = 0;
|
||||
|
@@ -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();">
|
||||
</div>
|
||||
|
||||
@@ -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();">
|
||||
</div>
|
||||
<div class="col-auto text-center">
|
||||
|
@@ -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;
|
||||
|
@@ -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<any> = new EventEmitter<any>();
|
||||
@Output() change: EventEmitter<any> = new EventEmitter<any>();
|
||||
@@ -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 `<input>` 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 `<input>` 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<VocabularyEntry>) => {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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'],
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<div #sdRef="ngbDropdown" ngbDropdown class="input-group w-100">
|
||||
<input class="form-control"
|
||||
<div #sdRef="ngbDropdown" ngbDropdown class="w-100">
|
||||
<input ngbDropdownToggle class="form-control custom-select"
|
||||
[attr.autoComplete]="model.autoComplete"
|
||||
[class.is-invalid]="showErrorMessages"
|
||||
[dynamicId]="bindId && model.id"
|
||||
@@ -11,12 +11,6 @@
|
||||
(click)="$event.stopPropagation(); openDropdown(sdRef);"
|
||||
(focus)="onFocus($event)"
|
||||
(keypress)="$event.preventDefault()">
|
||||
<button aria-describedby="collectionControlsMenuLabel"
|
||||
class="ds-form-input-btn btn btn-outline-primary"
|
||||
id="scrollableDropdownMenuButton_{{model.id}}"
|
||||
ngbDropdownToggle
|
||||
[disabled]="model.readOnly"
|
||||
(click)="onToggle(sdRef); $event.stopPropagation();"></button>
|
||||
|
||||
<div ngbDropdownMenu
|
||||
class="dropdown-menu scrollable-dropdown-menu w-100"
|
||||
|
@@ -126,7 +126,7 @@ describe('Dynamic Dynamic Scrollable Dropdown component', () => {
|
||||
});
|
||||
|
||||
it('should display dropdown menu entries', () => {
|
||||
const de = scrollableDropdownFixture.debugElement.query(By.css('button.ds-form-input-btn'));
|
||||
const de = scrollableDropdownFixture.debugElement.query(By.css('input.custom-select'));
|
||||
const btnEl = de.nativeElement;
|
||||
|
||||
const deMenu = scrollableDropdownFixture.debugElement.query(By.css('div.scrollable-dropdown-menu'));
|
||||
@@ -153,7 +153,7 @@ describe('Dynamic Dynamic Scrollable Dropdown component', () => {
|
||||
it('should select a results entry properly', fakeAsync(() => {
|
||||
const selectedValue = Object.assign(new VocabularyEntry(), { authority: 1, display: 'one', value: 1 });
|
||||
|
||||
let de: any = scrollableDropdownFixture.debugElement.query(By.css('button.ds-form-input-btn'));
|
||||
let de: any = scrollableDropdownFixture.debugElement.query(By.css('input.custom-select'));
|
||||
let btnEl = de.nativeElement;
|
||||
|
||||
btnEl.click();
|
||||
|
@@ -2,29 +2,29 @@ import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } fro
|
||||
import { FormGroup } from '@angular/forms';
|
||||
|
||||
import { Observable, of as observableOf } from 'rxjs';
|
||||
import { catchError, distinctUntilChanged, tap } from 'rxjs/operators';
|
||||
import { catchError, distinctUntilChanged, map, tap } 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 { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
|
||||
import { DynamicScrollableDropdownModel } from './dynamic-scrollable-dropdown.model';
|
||||
import { PageInfo } from '../../../../../../core/shared/page-info.model';
|
||||
import { isNull, isUndefined } from '../../../../../empty.util';
|
||||
import { isEmpty } from '../../../../../empty.util';
|
||||
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
|
||||
import { VocabularyFindOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-find-options.model';
|
||||
import { getFirstSucceededRemoteDataPayload } from '../../../../../../core/shared/operators';
|
||||
import { PaginatedList } from '../../../../../../core/data/paginated-list';
|
||||
import { DsDynamicVocabularyComponent } from '../dynamic-vocabulary.component';
|
||||
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
|
||||
|
||||
/**
|
||||
* Component representing a dropdown input field
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-dynamic-scrollable-dropdown',
|
||||
styleUrls: ['./dynamic-scrollable-dropdown.component.scss'],
|
||||
templateUrl: './dynamic-scrollable-dropdown.component.html'
|
||||
})
|
||||
export class DsDynamicScrollableDropdownComponent extends DynamicFormControlComponent implements OnInit {
|
||||
export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyComponent implements OnInit {
|
||||
@Input() bindId = true;
|
||||
@Input() group: FormGroup;
|
||||
@Input() model: DynamicScrollableDropdownModel;
|
||||
@@ -38,25 +38,20 @@ export class DsDynamicScrollableDropdownComponent extends DynamicFormControlComp
|
||||
public pageInfo: PageInfo;
|
||||
public optionsList: any;
|
||||
|
||||
protected searchOptions: VocabularyFindOptions;
|
||||
|
||||
constructor(private vocabularyService: VocabularyService,
|
||||
private cdr: ChangeDetectorRef,
|
||||
constructor(protected vocabularyService: VocabularyService,
|
||||
protected cdr: ChangeDetectorRef,
|
||||
protected layoutService: DynamicFormLayoutService,
|
||||
protected validationService: DynamicFormValidationService
|
||||
) {
|
||||
super(layoutService, validationService);
|
||||
super(vocabularyService, layoutService, validationService);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.vocabularyService.getVocabularyEntries(this.searchOptions).pipe(
|
||||
this.updatePageInfo(this.model.maxOptions, 1)
|
||||
this.vocabularyService.getVocabularyEntries(this.model.vocabularyOptions, this.pageInfo).pipe(
|
||||
getFirstSucceededRemoteDataPayload(),
|
||||
catchError(() => observableOf(new PaginatedList(
|
||||
new PageInfo(),
|
||||
@@ -66,9 +61,15 @@ export class DsDynamicScrollableDropdownComponent extends DynamicFormControlComp
|
||||
.subscribe((list: PaginatedList<VocabularyEntry>) => {
|
||||
this.optionsList = list.page;
|
||||
if (this.model.value) {
|
||||
this.setCurrentValue(this.model.value);
|
||||
this.setCurrentValue(this.model.value, true);
|
||||
}
|
||||
this.pageInfo = list.pageInfo;
|
||||
|
||||
this.updatePageInfo(
|
||||
list.pageInfo.elementsPerPage,
|
||||
list.pageInfo.currentPage,
|
||||
list.pageInfo.totalElements,
|
||||
list.pageInfo.totalPages
|
||||
);
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
|
||||
@@ -76,22 +77,37 @@ export class DsDynamicScrollableDropdownComponent extends DynamicFormControlComp
|
||||
.subscribe((value) => {
|
||||
this.setCurrentValue(value);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an item from the result list to a `string` to display in the `<input>` field.
|
||||
*/
|
||||
inputFormatter = (x: VocabularyEntry): string => x.display || x.value;
|
||||
|
||||
/**
|
||||
* Opens dropdown menu
|
||||
* @param sdRef The reference of the NgbDropdown.
|
||||
*/
|
||||
openDropdown(sdRef: NgbDropdown) {
|
||||
if (!this.model.readOnly) {
|
||||
this.group.markAsUntouched();
|
||||
sdRef.open();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads any new entries
|
||||
*/
|
||||
onScroll() {
|
||||
if (!this.loading && this.pageInfo.currentPage <= this.pageInfo.totalPages) {
|
||||
this.loading = true;
|
||||
this.searchOptions.currentPage++;
|
||||
this.vocabularyService.getVocabularyEntries(this.searchOptions).pipe(
|
||||
this.updatePageInfo(
|
||||
this.pageInfo.elementsPerPage,
|
||||
this.pageInfo.currentPage + 1,
|
||||
this.pageInfo.totalElements,
|
||||
this.pageInfo.totalPages
|
||||
);
|
||||
this.vocabularyService.getVocabularyEntries(this.model.vocabularyOptions, this.pageInfo).pipe(
|
||||
getFirstSucceededRemoteDataPayload(),
|
||||
catchError(() => observableOf(new PaginatedList(
|
||||
new PageInfo(),
|
||||
@@ -101,49 +117,50 @@ export class DsDynamicScrollableDropdownComponent extends DynamicFormControlComp
|
||||
tap(() => this.loading = false))
|
||||
.subscribe((list: PaginatedList<VocabularyEntry>) => {
|
||||
this.optionsList = this.optionsList.concat(list.page);
|
||||
this.pageInfo = list.pageInfo;
|
||||
this.updatePageInfo(
|
||||
list.pageInfo.elementsPerPage,
|
||||
list.pageInfo.currentPage,
|
||||
list.pageInfo.totalElements,
|
||||
list.pageInfo.totalPages
|
||||
);
|
||||
this.cdr.detectChanges();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onBlur(event: Event) {
|
||||
this.blur.emit(event);
|
||||
}
|
||||
|
||||
onFocus(event) {
|
||||
this.focus.emit(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a change event and set the current value with the given value.
|
||||
* @param event The value to emit.
|
||||
*/
|
||||
onSelect(event) {
|
||||
this.group.markAsDirty();
|
||||
this.model.valueUpdates.next(event);
|
||||
this.change.emit(event);
|
||||
this.dispatchUpdate(event);
|
||||
this.setCurrentValue(event);
|
||||
}
|
||||
|
||||
onToggle(sdRef: NgbDropdown) {
|
||||
if (sdRef.isOpen()) {
|
||||
this.focus.emit(event);
|
||||
} else {
|
||||
this.blur.emit(event);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sets the current value with the given value.
|
||||
* @param value The value to set.
|
||||
* @param init Representing if is init value or not.
|
||||
*/
|
||||
setCurrentValue(value: any, init = false): void {
|
||||
let result: Observable<string>;
|
||||
|
||||
setCurrentValue(value): void {
|
||||
let result: string;
|
||||
if (isUndefined(value) || isNull(value)) {
|
||||
result = '';
|
||||
} else if (typeof value === 'string') {
|
||||
result = value;
|
||||
if (init) {
|
||||
result = this.getInitValueFromModel().pipe(
|
||||
map((value: FormFieldMetadataValueObject) => value.display)
|
||||
);
|
||||
} else {
|
||||
for (const item of this.optionsList) {
|
||||
if (value.value === (item as any).value) {
|
||||
result = this.inputFormatter(item);
|
||||
break;
|
||||
}
|
||||
if (isEmpty(value)) {
|
||||
result = observableOf('');
|
||||
} else if (typeof value === 'string') {
|
||||
result = observableOf(value);
|
||||
} else {
|
||||
result = observableOf(value.display)
|
||||
}
|
||||
}
|
||||
this.currentValue = observableOf(result);
|
||||
|
||||
this.currentValue = result;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -142,15 +142,13 @@ describe('DsDynamicTagComponent test suite', () => {
|
||||
it('should init component properly', () => {
|
||||
chips = new Chips([], 'display');
|
||||
expect(tagComp.chips.getChipsItems()).toEqual(chips.getChipsItems());
|
||||
|
||||
expect(tagComp.searchOptions).toBeDefined();
|
||||
});
|
||||
|
||||
it('should search when 3+ characters typed', fakeAsync(() => {
|
||||
spyOn((tagComp as any).vocabularyService, 'getVocabularyEntries').and.callThrough();
|
||||
spyOn((tagComp as any).vocabularyService, 'getVocabularyEntriesByValue').and.callThrough();
|
||||
|
||||
tagComp.search(observableOf('test')).subscribe(() => {
|
||||
expect((tagComp as any).vocabularyService.getVocabularyEntries).toHaveBeenCalled();
|
||||
expect((tagComp as any).vocabularyService.getVocabularyEntriesByValue).toHaveBeenCalled();
|
||||
});
|
||||
}));
|
||||
|
||||
@@ -232,7 +230,6 @@ describe('DsDynamicTagComponent test suite', () => {
|
||||
it('should init component properly', () => {
|
||||
chips = new Chips(modelValue, 'display');
|
||||
expect(tagComp.chips.getChipsItems()).toEqual(chips.getChipsItems());
|
||||
expect(tagComp.searchOptions).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -259,7 +256,6 @@ describe('DsDynamicTagComponent test suite', () => {
|
||||
it('should init component properly', () => {
|
||||
chips = new Chips([], 'display');
|
||||
expect(tagComp.chips.getChipsItems()).toEqual(chips.getChipsItems());
|
||||
expect(tagComp.searchOptions).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should add an item on ENTER or key press is \',\' or \';\'', fakeAsync(() => {
|
||||
|
@@ -1,11 +1,7 @@
|
||||
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
|
||||
import {
|
||||
DynamicFormControlComponent,
|
||||
DynamicFormLayoutService,
|
||||
DynamicFormValidationService
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core';
|
||||
import { Observable, of as observableOf } from 'rxjs';
|
||||
import { catchError, debounceTime, distinctUntilChanged, map, merge, switchMap, tap } from 'rxjs/operators';
|
||||
import { NgbTypeahead, NgbTypeaheadSelectItemEvent } from '@ng-bootstrap/ng-bootstrap';
|
||||
@@ -13,7 +9,6 @@ import { isEqual } from 'lodash';
|
||||
|
||||
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
|
||||
import { DynamicTagModel } from './dynamic-tag.model';
|
||||
import { VocabularyFindOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-find-options.model';
|
||||
import { Chips } from '../../../../../chips/models/chips.model';
|
||||
import { hasValue, isNotEmpty } from '../../../../../empty.util';
|
||||
import { environment } from '../../../../../../../environments/environment';
|
||||
@@ -21,13 +16,18 @@ import { getFirstSucceededRemoteDataPayload } from '../../../../../../core/share
|
||||
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';
|
||||
import { DsDynamicVocabularyComponent } from '../dynamic-vocabulary.component';
|
||||
|
||||
/**
|
||||
* Component representing a tag input field
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-dynamic-tag',
|
||||
styleUrls: ['./dynamic-tag.component.scss'],
|
||||
templateUrl: './dynamic-tag.component.html'
|
||||
})
|
||||
export class DsDynamicTagComponent extends DynamicFormControlComponent implements OnInit {
|
||||
export class DsDynamicTagComponent extends DsDynamicVocabularyComponent implements OnInit {
|
||||
|
||||
@Input() bindId = true;
|
||||
@Input() group: FormGroup;
|
||||
@Input() model: DynamicTagModel;
|
||||
@@ -42,21 +42,28 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement
|
||||
hasAuthority: boolean;
|
||||
|
||||
searching = false;
|
||||
searchOptions: VocabularyFindOptions;
|
||||
searchFailed = false;
|
||||
hideSearchingWhenUnsubscribed = new Observable(() => () => this.changeSearchingStatus(false));
|
||||
currentValue: any;
|
||||
public pageInfo: PageInfo;
|
||||
|
||||
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 `<input>` field.
|
||||
*/
|
||||
formatter = (x: { display: string }) => x.display;
|
||||
|
||||
/**
|
||||
* Converts a stream of text values from the `<input>` element to the stream of the array of items
|
||||
* to display in the typeahead popup.
|
||||
*/
|
||||
search = (text$: Observable<string>) =>
|
||||
text$.pipe(
|
||||
debounceTime(300),
|
||||
@@ -66,8 +73,7 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement
|
||||
if (term === '' || term.length < this.model.minChars) {
|
||||
return observableOf({ list: [] });
|
||||
} else {
|
||||
this.searchOptions.query = term;
|
||||
return this.vocabularyService.getVocabularyEntries(this.searchOptions).pipe(
|
||||
return this.vocabularyService.getVocabularyEntriesByValue(term, false, this.model.vocabularyOptions, new PageInfo()).pipe(
|
||||
getFirstSucceededRemoteDataPayload(),
|
||||
tap(() => this.searchFailed = false),
|
||||
catchError(() => {
|
||||
@@ -83,16 +89,12 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement
|
||||
tap(() => this.changeSearchingStatus(false)),
|
||||
merge(this.hideSearchingWhenUnsubscribed));
|
||||
|
||||
/**
|
||||
* Initialize the component, setting up the init form value
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.hasAuthority = this.model.vocabularyOptions && hasValue(this.model.vocabularyOptions.name);
|
||||
|
||||
if (this.hasAuthority) {
|
||||
this.searchOptions = new VocabularyFindOptions(
|
||||
this.model.vocabularyOptions.scope,
|
||||
this.model.vocabularyOptions.name,
|
||||
this.model.vocabularyOptions.metadata);
|
||||
}
|
||||
|
||||
this.chips = new Chips(
|
||||
this.model.value,
|
||||
'display',
|
||||
@@ -104,17 +106,24 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement
|
||||
const items = this.chips.getChipsItems();
|
||||
// Does not emit change if model value is equal to the current value
|
||||
if (!isEqual(items, this.model.value)) {
|
||||
this.model.valueUpdates.next(items);
|
||||
this.change.emit(event);
|
||||
this.dispatchUpdate(items);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the searching status
|
||||
* @param status
|
||||
*/
|
||||
changeSearchingStatus(status: boolean) {
|
||||
this.searching = status;
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark form group as dirty on input
|
||||
* @param event
|
||||
*/
|
||||
onInput(event) {
|
||||
if (event.data) {
|
||||
this.group.markAsDirty();
|
||||
@@ -122,6 +131,10 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a blur event containing a given value and add all tags to chips.
|
||||
* @param event The value to emit.
|
||||
*/
|
||||
onBlur(event: Event) {
|
||||
if (isNotEmpty(this.currentValue) && !this.instance.isPopupOpen()) {
|
||||
this.addTagsToChips();
|
||||
@@ -129,10 +142,10 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement
|
||||
this.blur.emit(event);
|
||||
}
|
||||
|
||||
onFocus(event) {
|
||||
this.focus.emit(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates model value with the selected value and add a new tag to chips.
|
||||
* @param event The value to set.
|
||||
*/
|
||||
onSelectItem(event: NgbTypeaheadSelectItemEvent) {
|
||||
this.chips.add(event.item);
|
||||
// this.group.controls[this.model.id].setValue(this.model.value);
|
||||
@@ -140,25 +153,34 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement
|
||||
|
||||
setTimeout(() => {
|
||||
// Reset the input text after x ms, mandatory or the formatter overwrite it
|
||||
this.currentValue = null;
|
||||
this.setCurrentValue(null);
|
||||
this.cdr.detectChanges();
|
||||
}, 50);
|
||||
}
|
||||
|
||||
updateModel(event) {
|
||||
this.model.valueUpdates.next(this.chips.getChipsItems());
|
||||
this.change.emit(event);
|
||||
/* this.model.valueUpdates.next(this.chips.getChipsItems());
|
||||
this.change.emit(event);*/
|
||||
this.dispatchUpdate(this.chips.getChipsItems());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new tag with typed text when typing 'Enter' or ',' or ';'
|
||||
* @param event the keyUp event
|
||||
*/
|
||||
onKeyUp(event) {
|
||||
if (event.keyCode === 13 || event.keyCode === 188) {
|
||||
event.preventDefault();
|
||||
// Key: Enter or ',' or ';'
|
||||
// Key: 'Enter' or ',' or ';'
|
||||
this.addTagsToChips();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent propagation of a key event in case of return key is pressed
|
||||
* @param event the key event
|
||||
*/
|
||||
preventEventsPropagation(event) {
|
||||
event.stopPropagation();
|
||||
if (event.keyCode === 13) {
|
||||
@@ -166,6 +188,15 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
this.currentValue = value;
|
||||
}
|
||||
|
||||
private addTagsToChips() {
|
||||
if (hasValue(this.currentValue) && (!this.hasAuthority || !this.model.vocabularyOptions.closed)) {
|
||||
let res: string[] = [];
|
||||
@@ -188,7 +219,7 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement
|
||||
// this.currentValue = '';
|
||||
setTimeout(() => {
|
||||
// Reset the input text after x ms, mandatory or the formatter overwrite it
|
||||
this.currentValue = null;
|
||||
this.setCurrentValue(null);
|
||||
this.cdr.detectChanges();
|
||||
}, 50);
|
||||
this.updateModel(event);
|
||||
|
@@ -19,6 +19,7 @@ import { FormFieldMetadataValueObject } from '../../../models/form-field-metadat
|
||||
import { createTestComponent } from '../../../../../testing/utils.test';
|
||||
import { AuthorityConfidenceStateDirective } from '../../../../../authority-confidence/authority-confidence-state.directive';
|
||||
import { ObjNgFor } from '../../../../../utils/object-ngfor.pipe';
|
||||
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
|
||||
|
||||
export let TYPEAHEAD_TEST_GROUP;
|
||||
|
||||
@@ -134,14 +135,14 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
|
||||
|
||||
it('should search when 3+ characters typed', fakeAsync(() => {
|
||||
|
||||
spyOn((typeaheadComp as any).vocabularyService, 'getVocabularyEntries').and.callThrough();
|
||||
spyOn((typeaheadComp as any).vocabularyService, 'getVocabularyEntriesByValue').and.callThrough();
|
||||
|
||||
typeaheadComp.search(observableOf('test')).subscribe();
|
||||
|
||||
tick(300);
|
||||
typeaheadFixture.detectChanges();
|
||||
|
||||
expect((typeaheadComp as any).vocabularyService.getVocabularyEntries).toHaveBeenCalled();
|
||||
expect((typeaheadComp as any).vocabularyService.getVocabularyEntriesByValue).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should set model.value on input type when VocabularyOptions.closed is false', () => {
|
||||
@@ -229,13 +230,20 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
|
||||
|
||||
});
|
||||
|
||||
describe('and init model value is not empty', () => {
|
||||
describe('when init model value is not empty', () => {
|
||||
beforeEach(() => {
|
||||
typeaheadFixture = TestBed.createComponent(DsDynamicTypeaheadComponent);
|
||||
typeaheadComp = typeaheadFixture.componentInstance; // FormComponent test instance
|
||||
typeaheadComp.group = TYPEAHEAD_TEST_GROUP;
|
||||
typeaheadComp.model = new DynamicTypeaheadModel(TYPEAHEAD_TEST_MODEL_CONFIG);
|
||||
(typeaheadComp.model as any).value = new FormFieldMetadataValueObject('test', null, 'test001');
|
||||
const entry = observableOf(Object.assign(new VocabularyEntry(), {
|
||||
authority: null,
|
||||
value: 'test',
|
||||
display: 'testDisplay'
|
||||
}));
|
||||
spyOn((typeaheadComp as any).vocabularyService, 'getVocabularyEntryByValue').and.returnValue(entry);
|
||||
spyOn((typeaheadComp as any).vocabularyService, 'getVocabularyEntryByID').and.returnValue(entry);
|
||||
(typeaheadComp.model as any).value = new FormFieldMetadataValueObject('test', null, null, 'testDisplay');
|
||||
typeaheadFixture.detectChanges();
|
||||
});
|
||||
|
||||
@@ -244,9 +252,11 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
|
||||
typeaheadComp = null;
|
||||
});
|
||||
|
||||
it('should init component properly', () => {
|
||||
expect(typeaheadComp.currentValue).toEqual(new FormFieldMetadataValueObject('test', null, 'test001'));
|
||||
});
|
||||
it('should init component properly', fakeAsync(() => {
|
||||
tick();
|
||||
expect(typeaheadComp.currentValue).toEqual(new FormFieldMetadataValueObject('test', null, null, 'testDisplay'));
|
||||
expect((typeaheadComp as any).vocabularyService.getVocabularyEntryByValue).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should emit change Event onChange and currentValue is empty', () => {
|
||||
typeaheadComp.currentValue = null;
|
||||
@@ -257,6 +267,42 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when init model value is not empty and has authority', () => {
|
||||
beforeEach(() => {
|
||||
typeaheadFixture = TestBed.createComponent(DsDynamicTypeaheadComponent);
|
||||
typeaheadComp = typeaheadFixture.componentInstance; // FormComponent test instance
|
||||
typeaheadComp.group = TYPEAHEAD_TEST_GROUP;
|
||||
typeaheadComp.model = new DynamicTypeaheadModel(TYPEAHEAD_TEST_MODEL_CONFIG);
|
||||
const entry = observableOf(Object.assign(new VocabularyEntry(), {
|
||||
authority: 'test001',
|
||||
value: 'test001',
|
||||
display: 'test'
|
||||
}));
|
||||
spyOn((typeaheadComp as any).vocabularyService, 'getVocabularyEntryByValue').and.returnValue(entry);
|
||||
spyOn((typeaheadComp as any).vocabularyService, 'getVocabularyEntryByID').and.returnValue(entry);
|
||||
(typeaheadComp.model as any).value = new FormFieldMetadataValueObject('test', null, 'test001');
|
||||
typeaheadFixture.detectChanges();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
typeaheadFixture.destroy();
|
||||
typeaheadComp = null;
|
||||
});
|
||||
|
||||
it('should init component properly', fakeAsync(() => {
|
||||
tick();
|
||||
expect(typeaheadComp.currentValue).toEqual(new FormFieldMetadataValueObject('test001', null, 'test001', 'test'));
|
||||
expect((typeaheadComp as any).vocabularyService.getVocabularyEntryByID).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should emit change Event onChange and currentValue is empty', () => {
|
||||
typeaheadComp.currentValue = null;
|
||||
spyOn(typeaheadComp.change, 'emit');
|
||||
typeaheadComp.onChange(new Event('change'));
|
||||
expect(typeaheadComp.change.emit).toHaveBeenCalled();
|
||||
expect(typeaheadComp.model.value).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -1,18 +1,13 @@
|
||||
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
|
||||
import {
|
||||
DynamicFormControlComponent,
|
||||
DynamicFormLayoutService,
|
||||
DynamicFormValidationService
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core';
|
||||
import { catchError, debounceTime, distinctUntilChanged, filter, map, merge, switchMap, tap } from 'rxjs/operators';
|
||||
import { Observable, of as observableOf, Subject } from 'rxjs';
|
||||
import { NgbTypeahead, NgbTypeaheadSelectItemEvent } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
|
||||
import { DynamicTypeaheadModel } from './dynamic-typeahead.model';
|
||||
import { VocabularyFindOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-find-options.model';
|
||||
import { isEmpty, isNotEmpty, isNotNull } from '../../../../../empty.util';
|
||||
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
|
||||
import { ConfidenceType } from '../../../../../../core/shared/confidence-type';
|
||||
@@ -20,13 +15,14 @@ import { getFirstSucceededRemoteDataPayload } from '../../../../../../core/share
|
||||
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';
|
||||
import { DsDynamicVocabularyComponent } from '../dynamic-vocabulary.component';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-dynamic-typeahead',
|
||||
styleUrls: ['./dynamic-typeahead.component.scss'],
|
||||
templateUrl: './dynamic-typeahead.component.html'
|
||||
})
|
||||
export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent implements OnInit {
|
||||
export class DsDynamicTypeaheadComponent extends DsDynamicVocabularyComponent implements OnInit {
|
||||
@Input() bindId = true;
|
||||
@Input() group: FormGroup;
|
||||
@Input() model: DynamicTypeaheadModel;
|
||||
@@ -37,26 +33,33 @@ export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent imp
|
||||
|
||||
@ViewChild('instance', { static: false }) instance: NgbTypeahead;
|
||||
|
||||
pageInfo: PageInfo;
|
||||
searching = false;
|
||||
searchOptions: VocabularyFindOptions;
|
||||
searchFailed = false;
|
||||
hideSearchingWhenUnsubscribed$ = new Observable(() => () => this.changeSearchingStatus(false));
|
||||
click$ = new Subject<string>();
|
||||
currentValue: any;
|
||||
inputValue: any;
|
||||
|
||||
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 `<input>` field.
|
||||
*/
|
||||
formatter = (x: { display: string }) => {
|
||||
return (typeof x === 'object') ? x.display : x
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a stream of text values from the `<input>` element to the stream of the array of items
|
||||
* to display in the typeahead popup.
|
||||
*/
|
||||
search = (text$: Observable<string>) => {
|
||||
return text$.pipe(
|
||||
merge(this.click$),
|
||||
@@ -67,8 +70,11 @@ export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent imp
|
||||
if (term === '' || term.length < this.model.minChars) {
|
||||
return observableOf({ list: [] });
|
||||
} else {
|
||||
this.searchOptions.query = term;
|
||||
return this.vocabularyService.getVocabularyEntries(this.searchOptions).pipe(
|
||||
return this.vocabularyService.getVocabularyEntriesByValue(
|
||||
term,
|
||||
false,
|
||||
this.model.vocabularyOptions,
|
||||
this.pageInfo).pipe(
|
||||
getFirstSucceededRemoteDataPayload(),
|
||||
tap(() => this.searchFailed = false),
|
||||
catchError(() => {
|
||||
@@ -86,36 +92,49 @@ export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent imp
|
||||
)
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the component, setting up the init form value
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.currentValue = this.model.value;
|
||||
this.searchOptions = new VocabularyFindOptions(
|
||||
this.model.vocabularyOptions.scope,
|
||||
this.model.vocabularyOptions.name,
|
||||
this.model.vocabularyOptions.metadata);
|
||||
if (this.model.value) {
|
||||
this.setCurrentValue(this.model.value, true);
|
||||
}
|
||||
|
||||
this.group.get(this.model.id).valueChanges.pipe(
|
||||
filter((value) => this.currentValue !== value))
|
||||
.subscribe((value) => {
|
||||
this.currentValue = value;
|
||||
this.setCurrentValue(this.model.value);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the searching status
|
||||
* @param status
|
||||
*/
|
||||
changeSearchingStatus(status: boolean) {
|
||||
this.searching = status;
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the input value with a FormFieldMetadataValueObject
|
||||
* @param event
|
||||
*/
|
||||
onInput(event) {
|
||||
if (!this.model.vocabularyOptions.closed && isNotEmpty(event.target.value)) {
|
||||
this.inputValue = new FormFieldMetadataValueObject(event.target.value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a blur event containing a given value.
|
||||
* @param event The value to emit.
|
||||
*/
|
||||
onBlur(event: Event) {
|
||||
if (!this.instance.isPopupOpen()) {
|
||||
if (!this.model.vocabularyOptions.closed && isNotEmpty(this.inputValue)) {
|
||||
if (isNotNull(this.inputValue) && this.model.value !== this.inputValue) {
|
||||
this.model.valueUpdates.next(this.inputValue);
|
||||
this.change.emit(this.inputValue);
|
||||
this.dispatchUpdate(this.inputValue);
|
||||
}
|
||||
this.inputValue = null;
|
||||
}
|
||||
@@ -129,29 +148,60 @@ export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent imp
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates model value with the current value
|
||||
* @param event The change event.
|
||||
*/
|
||||
onChange(event: Event) {
|
||||
event.stopPropagation();
|
||||
if (isEmpty(this.currentValue)) {
|
||||
this.model.valueUpdates.next(null);
|
||||
this.change.emit(null);
|
||||
this.dispatchUpdate(null);
|
||||
}
|
||||
}
|
||||
|
||||
onFocus(event) {
|
||||
this.focus.emit(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates current value and model value with the selected value.
|
||||
* @param event The value to set.
|
||||
*/
|
||||
onSelectItem(event: NgbTypeaheadSelectItemEvent) {
|
||||
this.inputValue = null;
|
||||
this.currentValue = event.item;
|
||||
this.model.valueUpdates.next(event.item);
|
||||
this.change.emit(event.item);
|
||||
this.setCurrentValue(event.item);
|
||||
this.dispatchUpdate(event.item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback functions for whenClickOnConfidenceNotAccepted event
|
||||
*/
|
||||
public whenClickOnConfidenceNotAccepted(confidence: ConfidenceType) {
|
||||
if (!this.model.readOnly) {
|
||||
this.click$.next(this.formatter(this.currentValue));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current value with the given value.
|
||||
* @param value The value to set.
|
||||
* @param init Representing if is init value or not.
|
||||
*/
|
||||
setCurrentValue(value: any, init = false): void {
|
||||
let result: string;
|
||||
if (init) {
|
||||
this.getInitValueFromModel()
|
||||
.subscribe((value: FormFieldMetadataValueObject) => {
|
||||
this.currentValue = value;
|
||||
});
|
||||
} else {
|
||||
if (isEmpty(value)) {
|
||||
result = '';
|
||||
} else if (typeof value === 'string') {
|
||||
result = value;
|
||||
} else {
|
||||
result = value.display;
|
||||
}
|
||||
|
||||
this.currentValue = result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,12 +1,10 @@
|
||||
import { FieldParser } from './field-parser';
|
||||
import { isNotEmpty } from '../../../empty.util';
|
||||
import { VocabularyFindOptions } from '../../../../core/submission/vocabularies/models/vocabulary-find-options.model';
|
||||
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
|
||||
import { DynamicListCheckboxGroupModel } from '../ds-dynamic-form-ui/models/list/dynamic-list-checkbox-group.model';
|
||||
import { DynamicListRadioGroupModel } from '../ds-dynamic-form-ui/models/list/dynamic-list-radio-group.model';
|
||||
|
||||
export class ListFieldParser extends FieldParser {
|
||||
searchOptions: VocabularyFindOptions;
|
||||
|
||||
public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any {
|
||||
const listModelConfig = this.initModel(null, label);
|
||||
|
@@ -1,22 +1,13 @@
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import {
|
||||
DYNAMIC_FORM_CONTROL_TYPE_ARRAY,
|
||||
DynamicFormGroupModelConfig
|
||||
} from '@ng-dynamic-forms/core';
|
||||
|
||||
import { DYNAMIC_FORM_CONTROL_TYPE_ARRAY, DynamicFormGroupModelConfig } from '@ng-dynamic-forms/core';
|
||||
import { uniqueId } from 'lodash';
|
||||
|
||||
import { VocabularyFindOptions } from '../../../../core/submission/vocabularies/models/vocabulary-find-options.model';
|
||||
import { isEmpty } from '../../../empty.util';
|
||||
import { DynamicRowGroupModel } from '../ds-dynamic-form-ui/models/ds-dynamic-row-group-model';
|
||||
import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from '../ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model';
|
||||
import { FormFieldModel } from '../models/form-field.model';
|
||||
import {
|
||||
CONFIG_DATA,
|
||||
FieldParser,
|
||||
INIT_FORM_VALUES,
|
||||
PARSER_OPTIONS,
|
||||
SUBMISSION_ID
|
||||
} from './field-parser';
|
||||
import { CONFIG_DATA, FieldParser, INIT_FORM_VALUES, PARSER_OPTIONS, SUBMISSION_ID } from './field-parser';
|
||||
import { ParserFactory } from './parser-factory';
|
||||
import { ParserOptions } from './parser-options';
|
||||
import { ParserType } from './parser-type';
|
||||
@@ -48,8 +39,6 @@ export class RowParser {
|
||||
group: [],
|
||||
};
|
||||
|
||||
const vocabularyOptions = new VocabularyFindOptions(scopeUUID);
|
||||
|
||||
const scopedFields: FormFieldModel[] = this.filterScopedFields(rowData.fields, submissionScope);
|
||||
|
||||
const layoutDefaultGridClass = ' col-sm-' + Math.trunc(12 / scopedFields.length);
|
||||
@@ -58,7 +47,7 @@ export class RowParser {
|
||||
const parserOptions: ParserOptions = {
|
||||
readOnly: readOnly,
|
||||
submissionScope: submissionScope,
|
||||
collectionUUID: vocabularyOptions.collection
|
||||
collectionUUID: scopeUUID
|
||||
};
|
||||
|
||||
// Iterate over row's fields
|
||||
|
Reference in New Issue
Block a user