【问题标题】:md-autocomplete angular2 getting data from server (with a service)md-autocomplete angular2 从服务器获取数据(使用服务)
【发布时间】:2017-09-20 09:25:34
【问题描述】:

我想使用带有 angular2 / material2 的自动完成组件从服务器获取数据。 (https://material.angular.io/components/component/autocomplete)

ts

  emailCtrl: FormControl;
  filteredEmails: any;

  constructor(
    private companieService: CompanieService,
  ) {
    this.emailCtrl = new FormControl();
    this.filteredEmails = this.emailCtrl.valueChanges
        .startWith(null)
        .map(email => this.filterEmails(email));
  }


  filterEmails(email: string) {
    this.userService.getUsersByEmail(email)
      .subscribe(
        res => {
          return res
        },
        error => {
          console.log(error);
        }
      )
  }

html

    <md-input-container>
      <input mdInput placeholder="Email" [mdAutocomplete]="auto" [formControl]="emailCtrl" [(ngModel)]="fetchedUser.profile.email">
    </md-input-container>

    <md-autocomplete #auto="mdAutocomplete">
      <md-option *ngFor="let email of filteredEmails | async" [value]="email">
        {{email}}
      </md-option>
    </md-autocomplete>

服务:userService.getUsersByEmail(email) 正在拉这种数据:

 ['email1@email.com','email2@email.com','email3@email.com']

我没有错误,但在自动完成中没有结果。 我在 chrome (tab network) 的调试器中看到输入中的每个更改都正确提取数据

【问题讨论】:

  • 当用户点击输入框而不是等待输入第一个字母时,有什么办法让它显示全部可用?

标签: angular autocomplete angular-material


【解决方案1】:

我会给你我经常使用的例子,

this.SearchForm.controls['city_id'].valueChanges
  .debounceTime(CONFIG.DEBOUNCE_TIME)
  .subscribe(name => {
    this.domain = [['name', 'ilike', name]];
    this.DataService.getAutoComplete('res.city', this.domain)
      .subscribe(res => {
        return this._filteredCity = res['result']['records']
    })
  })

HTML

<div class="mb-1 ml-1 mt-1" fxFlex="30">
  <md-input-container style="width: 100%">
    <input mdInput placeholder="Kota" (blur)="checkAutoComplete('city_id')" [mdAutocomplete]="city_id" [required]="true" [formControl]="SearchForm.controls['city_id']">
  </md-input-container>
  <md-autocomplete #city_id="mdAutocomplete" [displayWith]="displayFn">
    <md-option *ngFor="let city of _filteredCity" [value]="city">
      <span>{{ city.name }}</span>
    </md-option>
  </md-autocomplete>
  <div *ngIf="SearchForm.controls['city_id'].hasError('required') && SearchForm.controls['city_id'].touched" class="mat-text-warn text-sm">Kolom ini wajib diisi.</div>
</div>

就这样

【讨论】:

  • 当用户点击输入框而不是等待输入第一个字母时,有什么办法让它显示全部可用?
【解决方案2】:

我就是这样做的。

.html

       <input formControlName="search" [mdAutocomplete]="auto" type="text" class="form-control">
 <md-autocomplete #auto="mdAutocomplete">
     <md-option *ngFor="let data of filteredData | async" [value]="data.text">
    {{ data.text }}
     </md-option>
 </md-autocomplete>

.ts

 filteredData: Observable<any[]>; // async pipe needs to be an Observable
 myContent: any[] = [];

 this.filteredData = this.myformGroup.get('search').valueChanges
 .debounceTime(400)
 .switchMap(value => {

  // get data from the server. my response is an array [{id:1, text:'hello world'}] as an Observable
  return  this.myApiService.getSearch(value); 

}).map(res => this.myContent = res);

让我知道这是否适合你。

【讨论】:

  • 搜索不在此解决方案中,显示的结果基于以前的搜索键...
  • 不,它不是以前的,因为如果你想对每个 keyup 值发出请求,只需删除这个:let exist = this.myContent.findIndex(t =&gt; t.text === value); if (exist &gt; -1) return;
  • - 你应该使用 switchMap 而不是 switchMap 来处理先前正在进行的请求并返回 this.myApiService.getSearch() (从这里完全删除订阅 - 删除延迟 500,因为 switchMap 处理我们的请求等待 -然后添加直接写入 this.filteredData 的订阅。还记得取消订阅或使用 takeUntil / takeWhile 和 ngOnDestroy 方法。
  • @user1740331 是的!正如你提到的那样,我已经用mergeMap 运算符进行了重构。
  • @Robin mergeMap 不会停止正在进行的 API 调用,您的响应以随机顺序到达。在stackoverflow.com/a/42227335/1740331 上查看弹珠
【解决方案3】:

my.component.html

<form [formGroup]="myForm">
  <mat-form-field>
    <input matInput
        formControlName="email"
        [matAutocomplete]="autoEmailGroup"
        name="email"
        type="email"
        placeholder="Email"
        aria-label="Email" />
    <mat-autocomplete
        autoActiveFirstOption
        #autoEmailGroup="matAutocomplete">
      <mat-option
          *ngFor="let email of emailOptions | async"
          [value]="email">{{ email }}</mat-option>
    </mat-autocomplete>
  </mat-form-field>
</form>

my.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, FormControl } from '@angular/forms';

import { Observable } from 'rxjs';
import { startWith, tap, switchMap, map, filter } from 'rxjs/operators';
import { empty } from 'rxjs/observable/empty';

@Component({
  selector: 'my-component',
  templateUrl: './my.component.html',
  styleUrls: ['./my.component.scss']
})
export class MyComponent implements OnInit {

  myForm: FormGroup;
  emailOptions: Observable<string[]>;

  constructor(
    private fb: FormBuilder,
    private http: HttpClient,
  ) { }

  createForm() {
    this.myForm = this.fb.group({
      email: new FormControl(),
    });

    const _fetchEmailsFromServer = (): Observable<string[]> => {
      // TODO you need to ultilize your service here
      return empty();
    };

    this.emailOptions = this.myForm.get('email')!.valueChanges
      .pipe(

        startWith(''),

        switchMap((input: string) => {
          return _fetchEmailsFromServer().pipe(

            // handle your HTTP response here
            map((response: any): string[] => {
              return <string[]> response!.data!.emails;
            }),

            tap((emails: string[]) => {
              // LOGGING
              console.log('Received emails:', emails);
            }),

            // you can filter emails fetched from your server here if you want
          );
        }),

      ).pipe(

        // default value to be displayed before HTTP task is completed
        startWith([]),
      );
  }

}

参考:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-25
    • 1970-01-01
    • 1970-01-01
    • 2014-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多