web-dev-qa-db-ja.com

Angularリアクティブフォームのないマテリアルマットオートコンプリート

<mat-autocomplete> from 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>

今のところ、JSにはconsole.logのみがあり、何が呼び出されているか、どの値で表示されているのかを確認するため、ここでは共有しません。適切な属性、適切なロジックを使用していますか?

(私のコンポーネントのmembersプロパティはRxjs BehaviourSubjectです)

listFilterValueには何も設定されていないため、今は何もしません。

9

テンプレート内のメソッドの呼び出しは避ける必要があります。これにより、各変更検出で呼び出されるため、ブラウザーがクラッシュする可能性があります。 * ngangular2で無限ループを実行する場合 技術的には無限ループではありませんが、ポイントを取得:)

オートコンプリートでフォームコントロールを持たないことはそれほど変わりません。代わりにフォームコントロールを変数に交換するだけで、必要に応じてテンプレート駆動フォームを使用することも、フォームをまったく使用しないこともできます。ただし、テンプレート駆動型のフォームは次のとおりです。

これで使用されるデモ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 Demo

17
AJT82