自动完成 angular 材料

Autocomplete with angular materials

我需要一些有关使用 angular 材料自动完成字段的帮助。首先,当页面加载时,我有一个服务对后端节点应用程序进行 API 调用,该应用程序将请求发送到 sanbox api。此调用带来了支持城市的列表。然后它提供具有表单的城市列表组件。当用户键入时,我想将城市缩小到一个自动完成框中。到目前为止,我已经将一个新变量设置为主题并使用 .filter() 和 .include() 方法来过滤数组并将其 return 到我的主题变量。 return 是我的订阅变量的对象形式,但现在在模板上我不能使用 returned 值来缩小我的结果。我认为这是因为我需要 return 我的结果到一个数组中。有人可以帮我概念化这个吗(目前我可以得到过滤器来缩小结果范围,但是数组在删除它们后不会重新加载值)

city-list Component.ts




import { CityService } from "./services/city-list.service";
import { Component, OnInit, OnDestroy } from "@angular/core";
import { City } from "../cities/models/city";
import { Subscription, Observable } from "rxjs";
import { map, startWith, debounceTime } from "rxjs/operators";
import {FormGroup, FormControl, Validators, NgForm} from '@angular/forms';


@Component({
  selector: "<app-cities></app-cities>",
  templateUrl: "./city-list.component.html"
})
export class CityListComponent implements OnInit, OnDestroy {

  cities: City[];
  private citiesSub: Subscription;
  destinationCity: FormControl = new FormControl();
  currentCity: Subscription;
  filteredCities: City[];

  constructor(public cityService: CityService) {}

  ngOnInit() {

    this.cityService.getCities();
    this.citiesSub = this.cityService
      .getCityUpdateListener()
      .subscribe((cities) => {
       this.cities = cities;

      });
   this.currentCity = this.destinationCity.valueChanges.pipe(
    debounceTime(400),
      startWith(''),
  ).subscribe(term=>{
    if(!term){
      return;
    }
    this._filter(term);
  }
  );
  }
  private _filter(value: string): City[] {
    const filterValue = value.toLowerCase();
    return this.filteredCities = this.cities.filter(option => option.name.toLocaleLowerCase().includes(filterValue));
  }
  ngOnDestroy() {
    this.citiesSub.unsubscribe();
  }

  onSearch(form: NgForm){
    console.log(form.value);
  }
}

city service.ts

import { Subject } from 'rxjs';
import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';

import { map } from "rxjs/operators";

import {City} from '../models/city';


@Injectable({ providedIn: "root" })
export class CityService {
  cities: City[] = [];
  private updatedCities = new Subject<City[]>();


  constructor(private http: HttpClient) {}

 getCities() {
  this.http.get<{message: string; cities: City[]}>('http://localhost:3000/cities')
  .pipe(
    map((cityData)=>{
      return cityData.cities.map(city=>{
        return{
          code: city.code,
          name: city.name
        };
      });
    })
)
  .subscribe((transCity) => {
    this.cities = transCity;
   // console.log(this.cities);
    this.updatedCities.next([...this.cities]);

  });
  }

  getCityUpdateListener() {
    return this.updatedCities.asObservable();
  }

}

city-list.html

<mat-card>
  <form #instantFlight="ngForm">
    <mat-form-field>
      <input  type="text" id="destinationCity" name="destinationCity" matInput [formControl]="destinationCity" [matAutocomplete]="autoDestination">

      <mat-autocomplete #autoDestination="matAutocomplete">
        <mat-option *ngFor="let c of cities" [value]="c.code">
          {{c.name}} - {{c.code}}
        </mat-option>
      </mat-autocomplete>
    </mat-form-field>
    <button mat-raised-button type="submit">Search</button>
  </form>
</mat-card>

import { CityService } from "./services/city-list.service";
import { Component, OnInit, OnDestroy } from "@angular/core";
import { City } from "../cities/models/city";
import { Subscription, Observable } from "rxjs";
import { map, startWith, debounceTime } from "rxjs/operators";
import { FormGroup, FormControl, Validators, NgForm } from "@angular/forms";

@Component({
  selector: "<app-cities></app-cities>",
  templateUrl: "./city-list.component.html",
  styleUrls: ["./cities-list.component.css"]
})
export class CityListComponent implements OnInit, OnDestroy {
  cities: City[]=[];
  private citiesSub: Subscription;
  currentCity: Observable<City[]>;


  destinationCity: FormControl =  new FormControl();
  originCity: FormControl =  new FormControl();
  startDate: FormControl = new FormControl();



  constructor(public cityService: CityService) {}


  ngOnInit() {
    this.cityService.getCities();
    this.citiesSub = this.cityService
      .getCityUpdateListener()
      .subscribe(cities => {
        this.cities = cities;
    });
    this.currentCity = this.destinationCity.valueChanges
    .pipe(
      startWith(''),
      debounceTime(10),
      map(x=>{
        return this._filter(x);
      }
    ));
  }
private _filter(value: string): City[]{
  const filterValue = value.toLowerCase();
  return(this.cities.filter(option => option.name.toLowerCase().includes(filterValue)));
}

  ngOnDestroy() {
    this.citiesSub.unsubscribe();
  }
}
<mat-card>
  <form (submit)="onLogin(instantFlight)" #instantFlight="ngForm">
    <mat-form-field>
      <input  type="text" id="destinationCity" name="destinationCity" matInput [formControl]="destinationCity" [matAutocomplete]="autoDestination">

      <mat-autocomplete #autoDestination="matAutocomplete">
        <mat-option *ngFor="let c of currentCity | async" [value]="c.code">
          {{c.name}} - {{c.code}}
        </mat-option>
      </mat-autocomplete>
    </mat-form-field>
    <mat-form-field>
    <input  type="text" id="originCity" name="originCity" matInput [formControl]="originCity" [matAutocomplete]="autoOrigin">

    <mat-autocomplete #autoOrigin="matAutocomplete">
      <mat-option *ngFor="let c of cities" [value]="c.code">
        {{c.name}} - {{c.code}}
      </mat-option>
    </mat-autocomplete>
  </mat-form-field>
  <mat-form-field>
      <input matInput id="startDate" name="startDate" [formControl]="startDate" [matDatepicker]="picker" placeholder="Choose a date">
      <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
      <mat-datepicker #picker></mat-datepicker>
    </mat-form-field>
    <button mat-raised-button type="submit" color="accent">Search</button>
  </form>
</mat-card>