I am trying to use Autocomplete from Angular Material.
Their data is options: string[] = ['One', 'Two', 'Three'];
, but instead of that I have an object.
This is how I get the data from the object, which is in currencies.json:
list(): Observable<Currencies> {
return this._http.get('./assets/currencies.json') as unknown as Observable<Currencies>;
}
public currencies$ = this.getAllCurrencies();
getAllCurrencies(): Observable<Currencies> {
return this._currencyService.list();
}
Now this is how I tried to bind the autocomplete:
<ng-container *ngIf="currencies$ | async">
<mat-form-field appearance="fill">
<mat-label>Currency</mat-label>
<input id="currency" type="text" matInput placeholder="Select a currency. E.g. USD" [matAutocomplete]="auto" formControlName="currency">
<mat-autocomplete autoActiveFirstOption #auto="matAutocomplete">
<mat-option *ngFor="let currency of currencies$ | keyvalue" [value]="currency.key">
{{currency.key}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</ng-container>
this.currencies$ = this.formMain.valueChanges.pipe(
startWith(''),
map(value => this.currencies$.subscribe(data => data.currency.includes((value.toString().toUpperCase() || '')))),
);
But then I get this error:
TS2322: Type 'Observable' is not assignable to type 'Observable'. Property 'currency' is missing in type 'Subscription' but required in type 'Currencies'.
How can I fix this?
I have also tried it this way:
currencies?: Observable<string[]>;
this.currencies = this.formMain.valueChanges.pipe(
startWith(''),
map(value => this.currencies$.subscribe(data => data.currency.includes((value.toString().toUpperCase() || '')))),
);
but then I get this error:
TS2322: Type 'Observable' is not assignable to type 'Observable<string[]>'. Type 'Subscription' is missing the following properties from type 'string[]': length, pop, push, concat, and 28 more.
Also tried it without subscribe()
:
this.formMain.valueChanges.pipe(
startWith(''),
map(value => [this.currencies$].filter(currency => currency.includes(value)))
);
But then I get the error:
TS2339: Property 'includes' does not exist on type 'Observable'.
This is my code on StackBlitz and this is the official code of Angular Material on StackBlitz. I want the result to be exactly the same as the official code but with my own data.
CodePudding user response:
First of all, you use wrong interface for your object.
The code
export interface Currencies {
currency: string;
}
means that your data should be smth like:
{
currency: 'some string'
}
In case of your object you can use:
export type Currencies = Record<string, string>;
Secondly, you don't have to cast your http call:
this._http.get('./assets/currencies.json') as unknown as Observable<Currencies>;
just use generic version of http.get<T>
method:
this._http.get<Currencies>('./assets/currencies.json')
^^^^^^^^^^
Third, you should be using [formControl]
binding in your stackblitz because you don't have a wrapper with formGroup
:
formControlName="currency" => [formControl]="myControl"
Finally, while constructing currencies$
observable you need to continue work with Observable
by using switchMap
instead of map
rxjs operator:
currencies$ = this._currencyService.list().pipe(
switchMap((currencies) => {
return this.myControl.valueChanges.pipe(
startWith(''),
map((query) =>
Object.fromEntries(
Object.entries(currencies).filter(([key]) =>
key.includes(query.toUpperCase())
)
)
)
);
})
);