18

我尝试在<mat-autocomplete>不使用反应形式的情况下使用 Angular Material(不是 AngularJS)。但他们所有的例子都使用反应形式......

我尝试做的事情:
1. 当在 中输入内容时mat-input,进行 Ajax 调用以检索用户列表
2. 在自动完成中显示用户列表(显示用户名),但将用户存储为模型
3 . 当模型改变时,调用我选择的函数

现在我做那些疯狂的事情(我说疯狂是因为它看起来很多)。

<mat-form-field fxLayout>
  <input type="text"
             matInput fxFlex="100"
             [(ngModel)]="listFilterValue"
             (keyup)="memberInputChanged(input.value)"
             (change)="memberChanged()"
             *ngIf="isAutocompleteNeeded()"
             #input
             [matAutocomplete]="auto">
</mat-form-field>

<mat-autocomplete #auto="matAutocomplete" [displayWith]="getMemberAsStr">
       <mat-option *ngFor="let member of members | async" [value]="member">
          {{ getMemberAsStr(member) }}
       </mat-option>
</mat-autocomplete>

目前只有console.log在我的 JS 中才能看到叫什么,有什么价值,这里就不分享了。我是否使用了正确的属性、正确的逻辑?

members我的组件中的属性是一个 Rxjs BehaviourSubject)

我现在所做的不起作用,因为listFilterValue从来没有设置任何东西。

4

1 回答 1

33

您应该避免在模板中调用方法,这可能会使您的浏览器崩溃,因为它们在每次更改检测时都会被调用,请参阅:*ngFor running an infinite loop in angular2从技术上讲,这不是一个无限循环,但您明白了 :)

至于没有自动完成的表单控件并没有太大的不同,您只需将表单控件交换为变量,如果需要,您可以使用模板驱动的表单,或者根本不使用表单。这是模板驱动的表单:

此处使用的演示 JSON 如下所示:

"value": [
  {
    "id": 409,
    "joke": "some joke here",
    "categories": []
  }
]
<form #f="ngForm">
  <mat-form-field>
    <input matInput [matAutocomplete]="auto" 
           name="joke" #jokeField="ngModel" 
           [(ngModel)]="currentJoke" (ngModelChange)="doFilter()">
  </mat-form-field>

  <mat-autocomplete #auto="matAutocomplete">
    <mat-option *ngFor="let joke of jokes | async" [value]="joke.joke">
        {{joke.joke}}
    </mat-option>
  </mat-autocomplete>
</form>

您的 TS 可能如下所示:

doFilter() {
  this.jokes = this.service.getData()
    .pipe(
      map(jokes => this.filter(jokes.value)),
  )
}

filter(values) {
  return values.filter(joke => 
    // used 'includes' here for demo, you'd want to probably use 'indexOf'
    joke.joke.toLowerCase().includes(this.currentJoke))
}

然后服务将有一个变量,我们在第一次获取后存储 api 数据,这样我们就不会在每次击键时调用 api。当数据返回时,我们检查变量是否已经被填充,如果是,我们返回一个可观察的:

jokes = [];

getData() {
  return this.jokes.length ? of(this.jokes)
    : this.httpClient.get<any>('https://api.icndb.com/jokes/random/5').pipe(
      map((data) => {
        this.jokes = data.value;
        return this.jokes;
      })
    )
}

如果导航离开,请记住清除jokes阵列。

StackBlitz 演示

于 2018-01-29T19:03:17.063 回答