如何基于Observable数据源实现Angular Material可筛选Autocomplete?
结合Angular Material Autocomplete与Observable数据源(基于自定义Store)
直接上实现方案,分组件类、模板、模块配置三部分,结合你提供的CoinApiStore完成对接:
1. 组件类实现
在组件中引入响应式表单控件和CoinApiStore,通过监听输入框的valueChanges触发Store的筛选逻辑:
import { Component, OnInit } from '@angular/core'; import { FormControl } from '@angular/forms'; import { Observable } from 'rxjs'; import { startWith, switchMap } from 'rxjs/operators'; import { CoinApiStore } from './path-to/coin-api-store.service'; import { Asset } from './path-to/asset.interface'; @Component({ selector: 'app-asset-autocomplete', templateUrl: './asset-autocomplete.component.html', styleUrls: ['./asset-autocomplete.component.css'] }) export class AssetAutocompleteComponent implements OnInit { assetControl = new FormControl(''); filteredAssets$!: Observable<Asset[]>; constructor(private coinApiStore: CoinApiStore) {} ngOnInit(): void { this.filteredAssets$ = this.assetControl.valueChanges.pipe( // 初始加载时显示默认的前10条数据 startWith(''), // 每次输入变化时调用Store的筛选方法,自动切换Observable switchMap(value => this.coinApiStore.getFilteredData(value?.toLocaleUpperCase() || '')) ); } // 自定义下拉选项的显示文本(适配Asset结构) displayAsset(asset: Asset): string { return asset ? (asset.name || asset.asset_id) : ''; } }
2. 模板实现
使用Angular Material的mat-autocomplete组件,绑定到我们定义的filteredAssets$,关联表单控件完成交互:
<mat-form-field appearance="fill"> <mat-label>选择资产</mat-label> <input type="text" matInput [formControl]="assetControl" [matAutocomplete]="auto"> <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayAsset"> <mat-option *ngFor="let asset of filteredAssets$ | async" [value]="asset"> {{ asset.name || asset.asset_id }} </mat-option> </mat-autocomplete> </mat-form-field>
3. 模块配置
确保你的模块中导入了必要的Angular Material和响应式表单模块:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ReactiveFormsModule } from '@angular/forms'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatInputModule } from '@angular/material/input'; import { MatFormFieldModule } from '@angular/material/form-field'; import { AssetAutocompleteComponent } from './asset-autocomplete.component'; @NgModule({ declarations: [AssetAutocompleteComponent], imports: [ CommonModule, ReactiveFormsModule, MatFormFieldModule, MatInputModule, MatAutocompleteModule ], exports: [AssetAutocompleteComponent] }) export class AssetAutocompleteModule {}
对Store代码的小优化建议
你当前的Store中private subject是冗余的,因为data$直接被赋值为接口请求的返回值,可简化为:
import { Injectable } from '@angular/core'; import { map, Observable, shareReplay } from 'rxjs'; import { HttpClient } from '@angular/common/http'; import { Asset } from '../interfaces/coin-api/asset'; @Injectable({ providedIn: 'root' }) export class CoinApiStore { private data$: Observable<Asset[]>; constructor(private http: HttpClient) { this.data$ = this.getDataFromCoinApi().pipe(shareReplay(1)); } public getData(): Observable<Asset[]> { return this.data$.pipe( map(assets => assets.sort(this.sortAssets).slice(0, 10)) ); } public getFilteredData(value: string): Observable<Asset[]> { return this.data$.pipe( map(assets => assets.filter(asset => asset.name?.toLocaleUpperCase().includes(value)).sort(this.sortAssets).slice(0, 10)) ); } private getDataFromCoinApi(): Observable<Asset[]> { const key = process.env['API_KEY']; const url = `https://rest.coinapi.io/v1/assets?apikey=${key}`; return this.http.get<Asset[]>(url); } private sortAssets(a1: Asset, a2: Asset) { return (a1.name ?? a1.asset_id).localeCompare((a2.name ?? a2.asset_id)); } }
内容的提问来源于stack exchange,提问作者Kiran
相关产品推荐
相关产品推荐

