0

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 Answer 1

2

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;
}
Sign up to request clarification or add additional context in comments.

6 Comments

Hi, I just had question, what if there are two strings? how will it differentiate here? for code and description? if (typeof value === "string") {
Also, I want [value]="dataSourceItem" to be code, not the whole class
this is close though appreciate it
maybe this? all this seems kind of messy, if (this.dataSource.find(x => x.code === filterData)) { dataSourceDescription = this.dataSource.find(x => x.code === filterData)?.description; } else { dataSourceDescription = filterData; } , however similar to this stackoverflow.com/a/55268844/15435022
if you want to use display with you have to pass the entire object, cause the function take the [value].
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.