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

时间:2017-01-16 12:04:26

标签: angular rxjs observable

我一直在调整Angular 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) ); 订阅。我不明白为什么某些形式的订阅似乎不被允许。

do

This plunker重现问题(打开DevTools控制台以查看错误):

  

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

第一种模式(format())确实不是非法的吗?

4 个答案:

答案 0 :(得分:2)

这让你的傻瓜工作:

  1. 在app.ts
  2. 中添加此导入语句
      import 'rxjs/add/operator/do';
    
    1. 在.do语句
    2. 之后删除分号
        

      .do(changes =&gt; {               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 {}
      

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

      在模板中更改此内容:

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

      在您处理组件中然后处理您的更改事件:

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

答案 1 :(得分:2)

其中一种方式是:

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

distinctUntilChanged 只会强制订阅实际值。

 this.form.controls['form_control_name']
            .valueChanges
            .debounceTime(MilliSeconds)
            .distinctUntilChanged()
            .subscribe(val => {

              });

答案 2 :(得分:0)

我也遇到了这个问题。

我想在我的情况下做debounceTime,所以它没有解决我的需求。

我其实忘了订阅!

但我能够通过这种方式获得价值变化:

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

来自Angular文档中的hero-detail-component.ts

答案 3 :(得分:0)

您可以订阅整个表单并选择要“接受”的内容,就像这样...此外,不要忘记跟踪订阅并使用生命周期钩子取消订阅。此外,请等到视图已加载以订阅更改。这种模式效果很好。

private DEBOUNCE_TIME_FORM_INPUT = 250

private ngUnsubscribe: Subscription = new Subscription();

constructor(private fb: FormBuilder) {} 

ngOnInit(): void {
  this.initForm();
}

ngAfterViewInit(): void {
  this.subscribeToFilters();
}

ngOnDestroy(): void { // Don't forget to close possible memory leak
  this.ngUnsubscribe.unsubscribe();
} 

private initForm(): void {
  this.form = this.fb.group({
    name: ['', []],  
  });
}

private subscribeToFilters(): void {
  this.ngUnsubscribe.add(
    this.form.valueChanges
      .pipe(debounceTime(this.DEBOUNCE_TIME_FORM_INPUT)) // Debounce time optional
      .subscribe((form): void => {
        const { name } = form
        console.log('Name', name);
    }))
  )
} 

get name(): AbstractControl { return this.form.get(['name']); }