Angular: Ng-select not displaying patched value in generic input field for edit/update

17 Views Asked by At

I have created a generic input field component in Angular 17 for reuse across my application. The component works well for various input types, but I encountered an issue when using it with ng-select for edit/update functionalities.

The problem arises when I try to patch a value into the ng-select field using the [value] binding. Despite successfully patching the value, it does not display in the field.

Here's a simplified version of my CustomInputComponent template:

<div *ngIf="data?.type == 'select'" class="flex flex-col">
    <label class="text-md" *ngIf="data.label">{{ data.label }}</label>
    <ng-select [disabled]="data.disabled!" [class.disabled]="data.disabled!" [value]="inputValue ? inputValue : ''"
        class="block {{class}} w-full text-sm text-gray-900 border border-gray-300 rounded-lg focus:ring-blue-500 focus:border-blue-500 "
        [items]="data.dropdown" bindLabel="{{data.bindLabel}}" [searchable]="data.searchable ? data.searchable: false"
        bindValue="{{data.bindValue}}" [formControl]="getFormControl()" (change)="onChangeEvent($event)"
        [placeholder]="data.placeholder">
    </ng-select>
    <div class="my-2 h-1">
        <div *ngIf="control?.hasError('required') && data?.required" class="text-red-500 text-xs  ">{{ data.label }} is
            required</div>
        <div *ngIf="!control?.hasError('required') && data.customErrorMessage && !getFormControl().value"
            class="text-red-500 text-xs">{{data.customErrorMessage}}</div>
    </div>
</div>

import { Component, EventEmitter, Input, Output, forwardRef } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CustomInput } from './custom-input.interface';
import { AbstractControl, ControlContainer, FormControl, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { MatInputModule } from '@angular/material/input';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatIconModule } from '@angular/material/icon';
import { NgSelectModule } from '@ng-select/ng-select';



@Component({
    selector: 'app-custom-input',
    standalone: true,
    imports: [CommonModule, MatInputModule, MatDatepickerModule, MatIconModule, NgSelectModule],
    templateUrl: './custom-input.component.html',
    styleUrl: './custom-input.component.scss',
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => CustomInputComponent),
            multi: true
        }
    ]
})
export class CustomInputComponent {
    //#region Input/Output
    isTooltipDate: any;
    selectSixtyDays: boolean = false;
    @Input() label: string;
    @Input() placeholder: string;
    @Input() class: string = 'dropDown_button_position';
    @Input() data: CustomInput;
    @Input() inputValue: string = '';
    @Output() change: EventEmitter<any> = new EventEmitter();
    @Output() onChange: EventEmitter<void> = new EventEmitter<void>();
    @Output() dropdownButton: EventEmitter<void> = new EventEmitter<void>();
    @Output() dropDownUpperButton: EventEmitter<void> = new EventEmitter<void>();
    @Output() dropdownValueChange: EventEmitter<string> = new EventEmitter<string>();
    //#endregion

    //#region Variable Initialization
    control: AbstractControl;
    selectedDate: any;
    //#endregion

    constructor(
        private controlContainer: ControlContainer,
    ) { }

    //#region Lifecycle methods

    ngOnInit() {
        this.getControlContainer();
    }



    getControlContainer() {
        if (this.controlContainer && this.data.name) {
            const control = this.controlContainer.control?.get(this.data.name) as AbstractControl;
            if (control) {
                this.control = control;
                this.getFormControl()?.addValidators([Validators.maxLength(this.data?.maxLength || 250)]);
                this.getFormControl()?.updateValueAndValidity();
                this.control.valueChanges.subscribe(value => {
                    this.inputValue = value;
                });

            } else {
                console.error(`Control with name '${this.data.name}' not found.`);
            }
        }
    }

    getFormControl(): FormControl {
        return this.data?.name ? this.controlContainer.control?.get(this.data.name) as FormControl : new FormControl();
    }

    onChangeEvent(event?: any) {
        this.control.setValue(event ?? null)
        this.change.emit(event ?? null);
        this.dropdownValueChange.emit(event);
    }

    onChangeEventHandler(event?: any) {
        this.change.emit(event ?? null);
    }

    onInputChange(event: Event) {
        const input = event.target as HTMLInputElement;
        const inputValue = input.value

        // Check if the input value contains at least one non-whitespace character
        let sanitizedValue = /^\s*\S/.test(inputValue) ? inputValue.replace(/[^A-Za-z ]/g, '') : '';

        this.getFormControl()?.setValue(sanitizedValue);
        this.onChangeEventHandler('e')
    }

    onNumberInputChange(event: Event, type?: string) {
        const input = event.target as HTMLInputElement;
        let sanitizedValue = input.value.replace(/[^0-9.]/g, '');

        sanitizedValue = sanitizedValue.replace(/^-/, '');
        this.getFormControl()?.setValue(sanitizedValue);
        this.onChangeEventHandler('e')
    }

    alphaNumericInputChange(event: Event) {
        const input = event.target as HTMLInputElement;
        const inputValue = input.value
        let sanitizedValue = /^\s*\S/.test(inputValue) ? inputValue.replace(/[^a-zA-Z0-9\s]/g, '') : '';
        this.getFormControl()?.setValue(sanitizedValue);
    }

    stringInputChange(event: Event) {
        const input = event.target as HTMLInputElement;
        const inputValue = input.value
        // Check if the input value contains at least one non-whitespace character
        let sanitizedValue = /^\s*\S/.test(inputValue) ? inputValue : '';
        this.getFormControl()?.setValue(sanitizedValue);
    }

    onCustomInputChange(event: Event) {
        const input = event.target as HTMLInputElement;
        const inputValue = input.value

        if (this.data.pattern) {
            const regexPattern = new RegExp(this.data.pattern, 'g');
            let sanitizedValue = /^\s*\S/.test(inputValue) ? inputValue.replace(regexPattern, '') : '';
            this.getFormControl()?.setValue(sanitizedValue);
        }
    }
    //#endregion
}

<div class="sm:col-span-12">
                                <app-custom-input [class]="'h-10'" [inputValue]="storeForm.get('storeType').value"
                                    [data]="{label: 'Store Type', required: true ,name:'storeType',type: 'select', searchable:true, dropdown:storeTypes, bindLabel:'name', bindValue:'name', placeholder: 'Select Store Type' }">
                                </app-custom-input>
                            </div>

The problem arises when I try to patch a value into the ng-select field using the [value] binding. Despite successfully patching the value, it does not display in the field.

0

There are 0 best solutions below