I'm facing a problem with my Angular Material 2 Autocomplete fields.
This is my setup:
hardwareCreate.component.ts
myControl: FormControl = new FormControl();
availableFirmware = [];
filteredFirmware: Observable<any[]>;
selectedFirmware = null;
selectedFirmwareName = '';
this.availableFirmware = [];
this.terminalService.getFirmware().subscribe(firmware => {
this.availableFirmware = firmware.firmware;
});
this.filteredFirmware = this.myControl.valueChanges
.pipe(
startWith(''),
map(val => this.filterFirmware(val))
);
filterFirmware(val: any): any[] {
return this.availableFirmware.filter(firmware => {
return firmware.name.toLowerCase().indexOf(val.toLowerCase()) > -1;
});
}
hardwareCreate.component.html
<div class="form-group">
<mat-form-field class="example-full-width">
<input type="text" placeholder="Firmware auswählen" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto1" [(ngModel)]="selectedFirmwareName">
<mat-autocomplete #auto1="matAutocomplete">
<mat-option *ngFor="let firmware of filteredFirmware | async" [value]="firmware._id">
{{ firmware.name }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
So my problem now is, that when I type I get the firmware.name attribute which is correct and looks like this:
But when I now select a firmware, the value
changes to the _id
of firmware
.
So I could change [value]="firmware._id"
to [value]="firmware.name"
but I need the ID for my mongodb ->
firmware: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Firmware'
},
Question: How can I change the display value to the name, but still get the Id for my Database when the user selects a specific firmware?
The solution now is a combination of both of vsoni and JEYs answers. The problem at the end was, that val
was an object. By converting it to a string, anything works like a charme!
Thanks to both of you!
You can use displayWith
function.
Your component.html would become
<div class="form-group">
<mat-form-field class="example-full-width">
<input type="text" placeholder="Firmware auswählen" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto1">
<mat-autocomplete #auto1="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngFor="let firmware of filteredFirmware | async" [value]="firmware" (onSelectionChange)="getXXX(firmware)>
{{ firmware.name }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
Then define following display function in you component.ts
displayFn(firmware: any): string {
return firmware? firmware.name : firmware;
}
You can access firmware id in getXXX(firmware)
function which you define in your component.ts. This function will be called on selection change.
getXXX(firmware) {
this.selectedFirmware = firmware;
// here you can get id
// firmware._id
}
and filter function
filterFirmware(val: any): any[] {
let name = val.name ? val.name : val;
return this.availableFirmware.filter(firmware => {
return firmware.name.toLowerCase().indexOf(name.toLowerCase()) > -1;
});
}
You can use the displayWith attribute like:
In your component:
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormControl } from '@angular/forms';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import { map } from 'rxjs/operators/map';
import {startWith} from 'rxjs/operators/startWith';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit, OnDestroy {
myControl = new FormControl();
availableFirmware = [{name: 'Firmware 1', id: 1}, {name: 'Firmware 2', id: 2}, {name: 'Firmware 3', id: 3}];
selected = null;
filteredFirmware: Observable<any>;
subcribtion: Subscription;
displayFirmware(firmware?: any) {
return firmware ? firmware.name : undefined;
}
filterFirmware(val: any): any[] {
return this.availableFirmware.filter(firmware => {
// when no selection occured value is a string
// but once a firmware is selected value is an object
let name = val.name ? val.name : val;
return firmware.name.toLowerCase().indexOf(name.toLowerCase()) === 0;
});
}
ngOnInit() {
this.subcribtion = this.myControl.valueChanges.subscribe(value => this.selected = value);
this.filteredFirmware = this.myControl.valueChanges.pipe(
startWith(''),
map(val => this.filterFirmware(val))
);
}
ngOnDestroy() {
this.subcribtion.unsubscribe();
}
}
In the template:
<div class="form-group">
<mat-form-field class="example-full-width">
<input type="text" placeholder="Firmware auswählen" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto1">
<mat-autocomplete #auto1="matAutocomplete" [displayWith]="displayFirmware">
<mat-option *ngFor="let firmware of filteredFirmware | async" [value]="firmware">
{{ firmware.name }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
<p>
{{selected | json}}
</p>
In this solution the value is the whole firmware object so you can retrieve anything from it.
You can find a running example here https://stackblitz.com/edit/angular-ptg4i1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With