web-dev-qa-db-ja.com

Angular 2のvalueChangesをサブスクライブする正しい方法

私はAngular 2.のリアクティブフォームとvalueChangesサブスクリプションをいじくり回しています。

this.form.get('name').valueChanges /* <- doesn't work */
  .do(changes => {
    console.log('name has changed:', changes)
    });
  .subscribe();

this.form.get('title').valueChanges.subscribe( /* <- does work */
  changes => console.log('title has changed:', changes)
);

このプランカー は問題を再現します(DevToolsコンソールを開いてエラーを確認します):

ZoneAwareError {stack: "Error:Uncaught(promise):TypeError:Cannotse…g.com/[email protected]/dist/zone.js:349:25)[]"、メッセージ: "Uncaught(in promise):TypeError:Array.forEach(ネイティブ)でprope…ore.umd.js:8486:93)↵を設定できません、originalStack:「Error:Uncaught(promise):TypeError:Cannot se…ps:// unpkg .com/zone.js @ 0.7.5/dist/zone.js:349:25) "、zoneAwareStack:"エラー:不明(約束):TypeError:se…g.com/[email protected]を設定できません/dist/zone.js:349:25)[] "、名前:「エラー」…}

最初のパターン(doを使用)は実際に違法ではありませんか?

8
user776686

方法の1つは次のとおりです。

debounceTimeは、指定されたミリ秒後にサブスクリプションを作成します。不要な場合は無視してください。

distinctUntilChangedは、実際の値の変更時にのみサブスクリプションを強制します。

Angular 8+

     this.form.controls['form_control_name']
                .valueChanges
                .pipe(
                    .debounceTime(MilliSeconds)
                    .distinctUntilChanged()
                )
                .subscribe({
                    next: (value) => {
                        //use value here
                    }
                });

これにより、プランカーが機能しました。

  1. このインポート文をapp.tsに追加します
  import 'rxjs/add/operator/do';
  1. .doステートメントの後のセミコロンを削除する

.do(changes => {console.log( 'name has changed:'、changes)})

完全に変更されたapp.ts

import {Component, NgModule, OnInit} from '@angular/core'
import {BrowserModule } from '@angular/platform-browser'
import { FormGroup, FormBuilder, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/do';

@Component({
  selector: 'my-app',
  template: `
    <form novalidate [formGroup]="form">
      <div>
        <select type="text" class="form-control" name="title" formControlName="title">
          <option *ngFor="let title of titles" value="{{title}}">{{title}}</option>
        </select>
      </div>
      <div>
        <input type="text" class="form-control" name="name" formControlName="name">
      </div>
      <fieldset formGroupName="address">
        <legend>Address</legend>
        <input type="text" class="form-control" name="street" formControlName="street">
        <input type="text" class="form-control" name="city" formControlName="city">
      </fieldset>
    </form>
  `,
})
export class App implements OnInit {
  private form: FormGroup;
  private titles: string[] =  ['Mr', 'Mrs', 'Ms'];

  constructor(private fb: FormBuilder){

  }
  ngOnInit() {
    this.form = this.fb.group({
      title: 'Mr',
      name: '',
      address: this.fb.group({
        street: '',
        city: ''
      })
    });

    this.form.get('name').valueChanges
      .do(changes => {
        console.log('name has changed:', changes)
        })
      .subscribe();

    this.form.get('title').valueChanges.subscribe(
      changes => console.log('title has changed:', changes)
    );

    this.form.get('address').valueChanges.subscribe(
      changes => console.log('address has changed:', changes)
    );  
  }
}

@NgModule({
  imports: [ BrowserModule, FormsModule, ReactiveFormsModule ],
  declarations: [ App ],
  bootstrap: [ App ]
})
export class AppModule {}

別の解決方法は、「ngModelChange」イベントを使用することです

テンプレートでこれを変更します。

 <input type="text" class="form-control" (ngModelChange)="doNameChange($event)" name="name" formControlName="name">

コンポーネントで、変更イベントを処理します。

doNameChange(event: any){
   alert("change")
}
2
Karl

私もこれに問題がありました。

私の場合はdebounceTimeを実行したかったので、私のニーズを解決できませんでした。

私は実際に購読するのを忘れていました!

しかし、この方法を有効にするために値の変更を取得することもできました。

this.form.get('name').valueChanges.forEach(
    (value) => {console.log(value);} )

ここからAngular docs: hero-detail-component.ts

1
JGFMK