填充数组并使其可使用 Angular Material 过滤
Posted
技术标签:
【中文标题】填充数组并使其可使用 Angular Material 过滤【英文标题】:Filling up an array and making it filterable with Angular Material 【发布时间】:2019-06-15 02:33:16 【问题描述】:我想在我的 Angular 应用启动时填充一个数组并将其用于 Material Autocomplete。我可以从我的 php 后端接收 JSON。在 ngOnInit 中,我什至可以将其提供给数组并将其注销。但是后来我的数组仍然未定义。我应该怎样做才能让内容最终显示在我的选项列表中?
app.component.html:
<form class="example-form">
<mat-form-field class="example-full-width">
<input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option of filteredOptions | async" [value]="option">
option
</mat-option>
</mat-autocomplete>
</mat-form-field>
</form>
app.component.ts:
import Component, OnInit, AfterViewInit from '@angular/core';
import FormControl from '@angular/forms';
import Observable from 'rxjs';
import map, startWith, takeUntil, switchMap from 'rxjs/operators';
import ServerService from './server.service';
/**
* @title Filter autocomplete
*/
@Component(
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css'],
)
export class AppComponent implements OnInit
myControl = new FormControl();
megyek: Observable<string[]>;
filteredOptions: Observable<string[]>;
constructor(private serverService: ServerService)
ngOnInit()
// don't manually subscribe!
this.megyek = this.serverService.getMegyek();
// use switchmap, if user types fast
this.filteredOptions = this.myControl.valueChanges.pipe(
startWith(''),
switchMap(value => this._filter(value))
);
private _filter(value: string): string[]
const filterValue = value.toLowerCase();
return this.megyek
.filter(option => option.toLowerCase().includes(filterValue));
app.module.ts
import BrowserModule from '@angular/platform-browser';
import NgModule from '@angular/core';
import ReactiveFormsModule, FormsModule from '@angular/forms';
import ServerService from './server.service';
import HttpModule from '@angular/http';
import AppComponent from './app.component';
import
MatButtonModule,
MatFormFieldModule,
MatInputModule,
MatRippleModule,
MatAutocompleteModule,
from '@angular/material';
import BrowserAnimationsModule from '@angular/platform-browser/animations';
@NgModule(
exports: [
MatButtonModule,
MatFormFieldModule,
MatInputModule,
MatRippleModule,
MatAutocompleteModule,
ReactiveFormsModule,
BrowserAnimationsModule,
FormsModule,
HttpModule
],
declarations: [],
imports: []
)
export class MaterialModule
@NgModule(
declarations: [
AppComponent
],
imports: [
MaterialModule,
BrowserModule,
],
providers: [ServerService],
bootstrap: [
AppComponent,
],
schemas: [],
)
export class AppModule
server.service.ts
import throwError as observableThrowError, Observable from 'rxjs';
import catchError, map from 'rxjs/operators';
import Injectable from '@angular/core';
import Headers, Http, Response from '@angular/http';
@Injectable()
export class ServerService
constructor(private http: Http)
storeServers(servers: any[])
const headers = new Headers('Content-Type': 'application/json');
// return this.http.post('https://udemy-ng-http.firebaseio.com/data.json',
// servers,
// headers: headers);
return this.http.put('https://udemy-ng-http.firebaseio.com/data.json',
servers,
headers: headers);
getMegyek()
return this.http.get('http://localhost/Varosok/Controller/ControllerCity.php?content=megyek').pipe(
map(
(response: Response) =>
console.log(response);
const data = response.json();
/*for (const megye of data)
megye.trim();
*/
return data;
),
catchError(
(error: Response) =>
console.log(error);
return observableThrowError('Something went wrong');
), );
getAppName()
return this.http.get('https://udemy-ng-http.firebaseio.com/appName.json').pipe(
map(
(response: Response) =>
return response.json();
));
【问题讨论】:
【参考方案1】:Your return value of array is any[] and you are now passing to an observable.
Change this (filteredOptions: Observable<string[]>) to (filteredOptions:any[])
change the ngOnit() code to this
(
this.serverService.getMegyek().pipe(**inside here you can use takeUntil to unsubscribe**)
.subscribe(
(megyek: any[]) =>
this.megyek = megyek;
console.log(this.megyek);
,
(error) => console.log(error)
);
)
if you html view use it like this: (
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option of filteredOptions" [value]="option">
option
</mat-option>
</mat-autocomplete>
*** Don't your array don't come out in a form of key:value? like opion.name and co..
if so, change this option to something like option.name
)
【讨论】:
将过滤选项修改为 any[] 并使用“.pipe(takeUntil(timer(100)))”。错误:“类型 'Observable请记住,您填充 megyek
的请求是异步的。所以当AfterViewInit
被执行时,megyek
没有值(还)但是是undefined
,因此它会抛出错误。保持 megyek
为 Observable,不要使用 AfterViewInit
。所以试试:
myControl = new FormControl();
megyek: Observable<string[]>;
filteredOptions: Observable<string[]>;
constructor(private serverService: ServerService)
ngOnInit()
// don't manually subscribe!
this.megyek = this.serverService.getMegyek();
// use switchmap, if user types fast
this.filteredOptions = this.myControl.valueChanges.pipe(
startWith(''),
switchMap(value => this._filter(value))
);
同样在您的过滤器中,您需要使用 map 来访问数组中的每个字段,并且我将其更改为带有 pipe
的 rxjs 6,看起来您正在使用它。
private _filter(value: string): Observable<string[]>
return this.megyek.pipe(
map(options => options.filter(option => option.toLowerCase().includes(value)))
)
演示:StackBlitz
【讨论】:
复制粘贴了您推荐的完全相同的代码,结果是 2 个错误:“类型 'ObservableObservable<string>
(来自 API 的响应?)这听起来很奇怪,因为您无法迭代字符串。您还在某处声明了string[]
。 filteredOptions
和 megyek
都应该是 Observable 数组,因此请检查您输入数据的方式。
好的,我看到我遇到了一个问题,我在过滤器函数中的返回类型错误。这就是后一个错误的来源(编辑后的答案)。对此感到抱歉;)但是Observable<string>
问题在您的代码中。
哦,必须尝试代码,看看有什么问题:D 里面混合了 rxjs 5 / 6,甚至我自己都没有注意到,部分原因是我们在处理这两个问题工作,所以自己感到困惑:D无论如何,答案已更新并添加了演示。请,将来您还可以创建一个演示该问题的演示,这样您就可以在有测试时更快地获得帮助(和正确答案哈哈)。
不客气,很高兴我们找到了解决方案……最后,在我搞砸了大部分事情之后:D 祝你有美好的一天,愉快的编码!一个小建议,我现在看到您正在使用 Http,它已被弃用并且已经使用了很长时间,请改用 HttpClient :) 有用的东西也随之而来,例如拦截器!看看:angular.io/guide/http以上是关于填充数组并使其可使用 Angular Material 过滤的主要内容,如果未能解决你的问题,请参考以下文章
您将使用啥架构来存储 100 亿条 MIME 消息并使其可删除和全文搜索,包括。附件
如何限制图例大小并使其可使用饼图滚动?和 javafx 布局