0
votes

I am trying to use a Angular Material Autocomplete with a class. I have Description shown in scroll-dropdown, and want actual value acquired in formValue to be Code.

For some reason everything works well, autocomplete will show all descriptions in scroll, but when I actually select a description value, a Code renders in textbox. It should still be showing the description, but store the Code value in the form. This was working fine when using mat-select dropdown, however transferring to autocomplete is causing some issues.

Is anyone familiar with how to resolve this?

enter image description here

Typescript:

 readonly dataSource = DataSource;
 dataSourceFilteredOptions: Observable<Array<BaseParentLookupVm>>;

  private _filterDataSource(value: string): Array<BaseParentLookupVm> {
    const filterValue = value?.toLowerCase() ?? '';
    let data = this.dataSource.filter(option => option.description.toLowerCase().includes(filterValue));
    return data;
  }

  createDataSourceFilteredOptions() {
    this.dataSourceFilteredOptions = this.processBatchForm.get('dataSourceField').valueChanges
      .pipe(
        startWith(''),
        map(value => this._filterDataSource(value))
      );
  } 

 public initializeNewBatchForm(): void {
   this.processBatchForm = this.formBuilder.group({
    'dataSourceField': [null, [Validators.required]],
  });
 }

HTML:

  <mat-form-field>
    <mat-label>Data Source</mat-label>
    <input 
      type="text"
      placeholder="Select"
      matInput
      formControlName="'dataSourceField'"
      [matAutocomplete]="templateDataSource">  
      <mat-autocomplete 
        #templateDataSource="matAutocomplete"
      >
      <mat-option>Select</mat-option>
      <mat-option 
        *ngFor="let dataSourceItem of dataSourceFilteredOptions | async" 
        [value]="dataSourceItem.code"
      >
        {{dataSourceItem.description}}
      </mat-option>
    </mat-autocomplete>
  </mat-form-field>

Supplemental Code:

export interface BaseParentLookupVm {
  displayOrderId?: number;
  code: string;
  description: string;
}

export const DataSource: Array<BaseParentLookupVm> = [
  { 
    displayCode: '1', 
    code: '1111', 
    description: '1111 Description'
  },
  { 
    displayCode: '2', 
    code: '2222', 
    description: '2222 Description' 
  },
  { 
    displayCode: '3', 
    description: '3333 Description' 
  },
  { 
    displayCode: '4', 
    description: '4444 Description'
  }
];

Resources:

This answer does straight mapping from value to description, so theirs works. Angular Autocomplete Object

Trying to update [DisplayWith] using textbox, Angular mat-autocomplete : How to display the option name and not the value in the input

This answer does not show how to work with textbox, giving another issue How to display using [displayWith] in AutoComplete Material2

1

1 Answers

1
votes

For using displayWith you have to change your code as:

<mat-form-field>
<mat-label>Data Source</mat-label>
<input 
  type="text"
  placeholder="Select"
  matInput
  formControlName="'dataSourceField'"
  [matAutocomplete]="templateDataSource">  
  <mat-autocomplete #templateDataSource="matAutocomplete" [displayWith]="displayFn">
  <mat-option>Select</mat-option>
  <mat-option 
    *ngFor="let dataSourceItem of dataSourceFilteredOptions | async" 
    [value]="dataSourceItem">
    {{dataSourceItem.description}}
  </mat-option>
</mat-autocomplete>

TS

myControl = new FormControl();
options = [{
    displayOrderId: 1,
    code: "1111",
    description: "1111 Description"
  },
  {
    displayOrderId: 2,
    code: "2222",
    description: "2222 Description"
  },
  {
    displayOrderId: 3,
    code: "3333",
    description: "3333 Description"
  },
  {
    displayOrderId: 4,
    code: "4444",
    description: "4444 Description"
  }
];
filteredOptions: Observable < any > ;

ngOnInit() {
  this.filteredOptions = this.myControl.valueChanges.pipe(
    startWith(""),
    map(value => this._filter(value))
  );
}

private _filter(value: any) {
  let filterValue = '';
  if (typeof value === "string") {
    filterValue = value.toLowerCase();
  } else {
    filterValue = value.description.toLowerCase();
  }

  return this.options.filter(
    option => option.description.toLowerCase().indexOf(filterValue) === 0
  );
}

displayFn(value: any) {
  return value ? value.description : undefined;
}