angular - 填充数组并使用 Angular Material 使其可过滤

标签 angular typescript angular-material

我想在我的 Angular 应用程序启动时填充一个数组,并将其用于 Material Autocomplete。我可以从我的 PHP 后端接收一个 JSON。在 ngOnInit 中,我什至可以将它提供给数组并将其注销。但是后来我的数组仍然未定义。我应该如何正确设置,以便内容最终显示在我的选项列表中?

应用程序组件.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>

应用程序组件.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));
  }
}

应用程序模块.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 { }

服务器.服务.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();
        }
      ));
  }
}

最佳答案

请记住,您填充 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

关于angular - 填充数组并使用 Angular Material 使其可过滤,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54294429/

相关文章:

angular - 如何替换以前选择的文件?

angular - 使用 ngFor 将枚举绑定(bind)到选择器中的选项

Angular 5,httpclient,跨域请求被阻止

typescript - 为什么 TypeScript 中没有重载构造函数实现?

javascript - Angular 2 应用程序在 system.src.js 加载时获得 404 core.js 和 browser.js

css - 如何使 Angular Material 按钮中的文本居中?

用 Material 编写的 Angular Testing 模板驱动形式

javascript - TS7006 : Parameter 'event' implicitly has an 'any' type

javascript - 为什么全局数组声明会使测试失败?

angular - 有没有办法检测用户何时导航到 Angular 中的另一个组件?