formio / angular

JSON powered forms for Angular
https://formio.github.io/angular-demo
MIT License
613 stars 461 forks source link

[Custom Components] Ability to optionally select multiple values in Custom Component #1055

Open muneebahmad0600 opened 2 months ago

muneebahmad0600 commented 2 months ago

I have a dropdown-like component that loads data from my back end. I need to have different view types for my component which I am able to achieve (i.e. Single-select dropdown, Multi-select dropdown, Radio, Checkbox). Single-select dropdown and Radio would mean the user can select 1 value and of course Multi-select and Checkbox meaning user can select multiple values.

image

when I select Multi-select in View Type dropdown and try to select the default value I get this.

image

I will paste the entire LOV component.

` export class CustomLovComponent implements FormioCustomComponent<string[]>, OnInit, OnChanges, OnDestroy { @Input() value: any = ''; @Input() disabled!: boolean; @Input() lovType!: string; @Input() viewType!: string;

@Output() valueChange = new EventEmitter(); @Output() formioEvent = new EventEmitter();

private destroy$ = new Subject();

loading = false; baseURL: string = this.configProvider.appSettings.coreApiUrl; lovOptionsResponse: Options[] = []; lovOptions: Options[] = []; showUI = true;

constructor( private readonly configProvider: ConfigurationProvider, private readonly http: HttpClient, private readonly lovOptionService: LovOptionsService, public cdr: ChangeDetectorRef ) {}

ngOnInit() { this.getAllLovs(); }

ngOnChanges(changes: SimpleChanges): void { this.showUI = false; this.lovType = changes['lovType']?.currentValue; if (this.viewType == 'dropdownMultiSelect' || this.viewType == 'checkbox') { this.value = typeof this.value == 'string' ? [] : this.value; } console.log('Insomniac: value', typeof this.value, this.value); this.showUI = true; this.getLOVOptions(); }

ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); }

private getLOVOptions(): void { if (!this.isObjectEmpty(this.lovType)) { this.loading = true; this.cdr.detectChanges(); this.lovOptionService .getOptions(this.lovType) .pipe(debounceTime(500), takeUntil(this.destroy$)) .subscribe((res: Options[]) => { this.lovOptionsResponse = res; this.lovOptions = res; this.loading = false; this.cdr.detectChanges(); }); } }

private getAllLovs(): void { if (AllLOVs.length) return; this.http .get(${this.baseURL}api/data/v1/lovtype?pageNo=1&pageSize=999) .pipe(takeUntil(this.destroy$)) .subscribe((res: any) => { AllLOVs = res.items; }); }

private isObjectEmpty(obj: any) { if (!obj) return true; return Object.keys(obj).length === 0; }

filterLovOptions(filterString: any): void { this.lovOptions = this.lovOptionsResponse.filter((lov) => lov.text.toLowerCase().includes(filterString.toLowerCase()) ); this.cdr.detectChanges(); }

valueUpdate(value: any): void { this.value = value; this.valueChange.emit(value); this.cdr.detectChanges(); // this.formioEvent.emit({ // eventName: 'refresh', // }); }

checkBoxUpdate(index: number, event: any): void { const isChecked = event.target.checked; if (isChecked) { this.value.push(this.lovOptions[index].value); } else { this.value.splice(this.value.indexOf(this.lovOptions[index].value), 1); } this.valueChange.emit(this.value); this.cdr.detectChanges(); }

getValueForMultiSelect(): any { return typeof this.value == 'string' ? [] : this.value; } }

export let AllLOVs: LovItems[] = [];

export const COMPONENT_OPTIONS: FormioCustomComponentInfo = { type: 'casexLov', selector: 'casex-lov', title: 'LOV', group: 'customBasic', icon: 'fa-thin fa-bars', editForm: editForm, };

export function registerLovComponent(injector: Injector) { if (!customElements.get(COMPONENT_OPTIONS.selector)) registerCustomFormioComponent( COMPONENT_OPTIONS, CustomLovComponent, injector ); }

export function editForm() { const components: ExtendedComponentSchema[] = [ { type: 'tabs', key: 'tabs', components: [ { key: 'data', components: [ // { // weight: 0, // type: 'checkbox', // label: 'Multiple Values', // tooltip: 'Allows multiple values to be entered for this field.', // key: 'multiple', // input: true, // }, { weight: 3, type: 'select', input: true, key: 'customOptions.lovType', label: 'Lov Type', placeholder: 'enter lov type', tooltip: 'Enter the LOV type to be used for this field. This is the LOV type that will be used to populate the dropdown list.', validate: { required: true, }, dataSrc: 'custom', valueProperty: 'value', data: { custom: function custom(context: any) { return AllLOVs.map((lov) => { return { label: lov.id, value: lov.id }; }); }, }, }, { type: 'select', label: 'View Type', key: 'customOptions.viewType', weight: 5, placeholder: 'View Type', tooltip: 'View Type will determine how the options will be shown', input: true, defaultValue: 'dropdownSingleSelect', data: { values: [ { label: 'Dropdown (Single Select)', value: 'dropdownSingleSelect', }, { label: 'Dropdown (Multi Select)', value: 'dropdownMultiSelect', }, { label: 'Radio', value: 'radio', }, { label: 'Checkbox', value: 'checkbox', }, ], }, }, { type: 'select', label: 'Default Value', key: 'defaultValue', weight: 8, placeholder: 'Default Value', tooltip: 'The Default Value will be the value for this field, before user interaction. Having a default value will override the placeholder text.', input: true, }, ], label: 'Data', weight: 10, }, ], }, { type: 'hidden', key: 'type', }, ]; return { components: components, }; } `

`<div ngIf="showUI"> <div [ngSwitch]="viewType"> <div ngSwitchCase="'dropdownSingleSelect'"> <ng-container [ngTemplateOutlet]="singleSelectDropdown">

<div *ngSwitchCase="'dropdownMultiSelect'"> <kendo-multiselect fillMode="outline" [data]="lovOptions" [value]="value" textField="text" valueField="value" [filterable]="true" [valuePrimitive]="true" [disabled]="loading" (valueChange)="valueUpdate($event)" (filterChange)="filterLovOptions($event)"

<div ngSwitchCase="'radio'"> <p ngIf="!lovOptions.length">Select an LOV Type to view options!

<div ngSwitchCase="'checkbox'"> <p ngIf="!lovOptions.length">Select an LOV Type to view options!

<div *ngSwitchDefault> <ng-container [ngTemplateOutlet]="singleSelectDropdown">

<ng-template #singleSelectDropdown> <kendo-dropdownlist fillMode="outline" [data]="lovOptions" [value]="value" textField="text" valueField="value" [valuePrimitive]="true" [filterable]="true" [disabled]="loading" (valueChange)="valueUpdate($event)" (filterChange)="filterLovOptions($event)"

`

muneebahmad0600 commented 2 months ago

@travist would appreciate a response on this.

gyanendrasinghpanwar commented 1 month ago

@muneebahmad0600 If i remember correctly, this has to do with the property multiple. I presume u need to set it true in custom component.