在Angular 2中订阅valueChanges的正确方法

use*_*686 8 observable rxjs angular

我一直在使用valueChangesAngular 2中的被动表单和订阅.我不明白为什么某些形式的订阅似乎不被允许.

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)
);
Run Code Online (Sandbox Code Playgroud)

这个plunker再现了问题(打开DevTools控制台以查看错误):

ZoneAwareError {stack:"错误:未捕获(在承诺中):TypeError:不能se...g.com/zone.js@0.7.5/dist/zone.js:349:25)[]",消息:"未捕获(在promise):TypeError:无法设置prope ... ore.umd.js:8486:93)↵在Array.forEach(native)",originalStack:"错误:未捕获(在承诺中):TypeError:不能se ... ps:// unpkg .com/zone.js @ 0.7.5/dist/zone.js:349:25)",zoneAwareStack:"错误:未捕获(承诺):TypeError:不能se...g.com/zone.js@0.7.5 /dist/zone.js:349:25)[]",名称:"错误"......}

第一种模式(有do)确实不违法吗?

Nab*_*ada 5

其中一种方法是:

debounceTime将在给定的毫秒后进行订阅。如果不需要,请忽略。

distinctUntilChanged将仅在实际值更改时强制订阅。

Angular 8+ 更新

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


Kar*_*arl 1

这让你的笨蛋开始工作:

  1. 在 app.ts 中添加此导入语句
  import 'rxjs/add/operator/do';
Run Code Online (Sandbox Code Playgroud)
  1. 删除 .do 语句后的分号

.do(changes => { console.log('名称已更改:', 更改) })

完成更改的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 {}
Run Code Online (Sandbox Code Playgroud)

另一种解决方法是使用“ngModelChange”事件

在您的模板中更改此设置:

 <input type="text" class="form-control" (ngModelChange)="doNameChange($event)" name="name" formControlName="name">
Run Code Online (Sandbox Code Playgroud)

在您的组件中,您可以处理更改事件:

doNameChange(event: any){
   alert("change")
}
Run Code Online (Sandbox Code Playgroud)

  • @user776686,你的模式语法没有错误。 (2认同)