Wednesday, 22 January 2020

Angular 8: Mat-Select List Dropdown with formControlName and ControlValueAccessor

I am trying to create a Material dropdown wrapper, (mat-select dropdown), which will take Id's from a class, and change the mat-select list data/description.

Requirements:

1) Needs to work with formControlName. We have parent component form with formBuilder/and its validators which is trying to refer to this child wrapper. The Parent Component formbuilder has many other form fields also, as typical scenarios.

2) Needs to show error red invalid, if data does not meet requirements of parent FormBuilder validators.

3) a) Needs to work not only with formControlName/patchValue (patchValue should work with whole class); b) if also if someone places data into @Input() SelectedValueId Id number. can work with the two

Attempting to get this working, but not successful yet, Does anyone have any code to fix this?

In this case, Id is sourceOfAddressId

export class SourceOfAddressDto implements ISourceOfAddressDto {
    sourceOfAddressId: number | undefined;  // should work with this Id
    sourceOfAddressCode: string | undefined;
    sourceOfAddressDescription: string | undefined;

Typescript:

@Component({
    selector: 'app-address-source-dropdown',
    templateUrl: './address-source-dropdown.component.html',
    styleUrls: ['./address-source-dropdown.component.scss'],
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => AddressSourceDropdownComponent),
            multi: true
        }
    ]
})
export class AddressSourceDropdownComponent implements OnInit, OnChanges {

    dataList: any[] = []; 
    @Input() Label = 'Address Source';
    @Input() sourceOfAddressDefaultItem: SourceOfAddressDto = SourceOfAddressDefault;
    @Input() selectedSourceOfAddress: any;
    @Input() TxtValue = 'sourceOfAddressId';
    @Input() TxtField = 'sourceOfAddressDescription';
    @Input() Disabled: boolean;
    @Input() valuesToExclude: number[] = [];
    @Input() Hint = '';
    @Input() styles: string;
    @Input() defaultSourceOfAddressCode: any;
    @Output() addressSourceChange = new EventEmitter<any>();

    private _selectedValueId: number;

    @Input() set selectedValueId(value: number) {
        this._selectedValueId = value;

        let outputData: any;
        if (this.selectedValueId == this.sourceOfAddressDefaultItem[this.TxtValue]) {
            outputData = null;
        } else {
            outputData = this.dataList.find(x => x[this.TxtValue] == this.selectedValueId);
        }

        this.onChange(outputData);
    }
    get selectedValueId(): any {
        return this._selectedValueId;
    }
    @Input() errors: any = null;
    disabled: boolean;
    control: FormControl;
    writeValue(value: any) {
        this.selectedValueId = value ? value : '';
    }
    onChange = (_: any) => { };
    onTouched: any = () => { };
    registerOnChange(fn: any) { this.onChange = fn; }
    registerOnTouched(fn: any) { this.onTouched = fn; }
    setDisabledState(isDisabled) { this.disabled = isDisabled; }

    constructor(
        public injector: Injector,
        private AddressService: AddressServiceProxy,
    ) { }

    ngOnInit() {
        this.loadDataList();
    }

    ngOnChanges() { }

    loadDataList() {
        this.AddressService.getSourceOfAddressAll().subscribe(res => {
            this.dataList = res.body.filter(q => q.sourceOfAddressId !== -1);
        });
    }

}

HTML:

<div class="dropdown-cont">
  <mat-form-field appearance="outline">
    <mat-label></mat-label>
    <mat-select 
      disableOptionCentering 
      [disabled]="Disabled" 
      [ngStyle]="styles" 

      (ngModelChange)="selectedValueId=$event"
        required>
      <mat-option [value]="sourceOfAddressDefaultItem[TxtValue]"></mat-option>
      <mat-option *ngFor="let item of dataList" [value]="item[TxtValue]">
        
      </mat-option>
    </mat-select>
    <mat-hint></mat-hint>
  </mat-form-field>
</div>
  • also hopefully works with default values, even if API is lagging sometimes, and default value is inserted first in @Input SelectedValueId


from Angular 8: Mat-Select List Dropdown with formControlName and ControlValueAccessor

No comments:

Post a Comment