Angular 5 - Observable - 将Observable的第一个值设置为formgroup

时间:2018-03-01 15:02:11

标签: angular forms observable

我的onInit方法中有一个Observable of Contacts,我也会将Observable的第一个联系人设置为我的表单。 有谁提示如何做到这一点?

ngOnInit() { 
    let contactsObservable: Observable<Contact[]> = 
    this.contactService.getAllContacts();
    contactsObservable.subscribe(contacts => {
        this.contacts = contacts; 
    });

    this.form = this.fb.group({ 
                // this.contacts[0] does not work
      contact: [this.contacts[0], [Validators.required]] // how to get contact[0] into form for presetting
    });
}

5 个答案:

答案 0 :(得分:1)

理想情况下,表单将位于您获取数据的子组件中。然后,您可以使用async管道将contactsObservable直接传递给表单,并同步使用这些值。

但是,为了在同一个OnInit挂钩中完成所有操作,最好的方法是为contactsObservable提供startWith值。只有当你知道每种情况下的第一个值是什么时,这才是可行的,如果你已经知道,那么你也可以使用有效的起始值来实例化表单控件:

this.form = this.fb.group({ 
  contact: [[ // some value ], [Validators.required]]
});

可以按照Roland在评论中提到的方式初始化订阅中的表单,但每次observable发出值时,这都会重新初始化您的表单。同样,从订阅中强制设置表单控件的值会冒着覆盖用户输入的输入或其他时髦行为的风险,具体取决于您的服务的工作方式。

这种方法的例子看起来像

contactsObservable.subscribe(contacts => {
  this.form = this.fb.group({
    contacts: [contacts, [...Validators]]
  })
});

或者

this.form = this.fb.group({
  contacts: [[], [...Validators]]
});
contactsObservable.subscribe(contacts => {
  this.form.get('contacts').setValue(contacts);
});

请注意,您可以使用setValuepatchValue,具体取决于您的需求。但是这种方法仍然有问题,因为它试图忽略数据的异步性质。 它会覆盖输入中当前的内容,因此如果在用户输入时更新数据,他们的输入将被清除并替换,这可能令人沮丧。另外,您需要处理清理订阅。

此模式未按预期工作的主要原因是您将异步值contacts视为同步。只需将其解压缩到组件中并将值保存到变量中,就不会消除通过Observable到达的值的异步性质。有关详细信息,请查看this resource

在我看来,最好的办法是将表单提取到一个单独的组件中,并利用Angular的async管道传递异步数据。

答案 1 :(得分:1)

您获得联系人异步。 当Observable返回值时,可以输入值。

ngOnInit() { 
   this.form = this.fb.group({ 
     contact: ['', [Validators.required]] 
   });
   let contactsObservable: Observable<Contact[]> = 
   this.contactService.getAllContacts();
   contactsObservable.subscribe(contacts => {
       this.contacts = contacts; 
       this.form.controls['contact'].setValue(this.contacts[0])
   });
}

答案 2 :(得分:1)

您可以使用Form patchValue来设置表单,因为 vincecampanale 指出更好地使用带有observable的Smart / Dumb Components模式然后在您的组件中可以设置

  @Input() set contactsList(contacts: any[]) {
    if (contacts) {
      this.form.patchValue({
        contact: contacts[0]
      });
    }
  }

答案 3 :(得分:0)

为什么不简单地将form的初始化放在subscribe()中?

ngOnInit() {
    // ...
    // .take(2) to ensure that it will run only for the first value:
    contactsObservable.take(1).subscribe(contacts => {
        this.form = this.fb.group({contact: [this.contacts[0], Validators.required]];
    });
    // ...
}

或者您可以在没有contact的情况下初始化表单,稍后将其添加到FormGroup

这将是异步的,但您可以在模板中设置*ngIf,如下所示:

<form *ngIf="form" ...>...</form>

答案 4 :(得分:0)

这对我来说适用于Angular 6.x:

 import {FormBuilder, FormGroup, Validators} from '@angular/forms';
 @Input() artist: Artist;
 artistForm: FormGroup;
 constructor(private route: ActivatedRoute, private artistService: ArtistService, private location: Location, private fb: FormBuilder)  { this.createForm(); }


 ngOnInit() {
 this.getArtist();
}

   createForm(){
this.artistForm = this.fb.group({
  ArtistName: ['', Validators.required]

 });
}


   getArtist(): void{
const id = +this.route.snapshot.paramMap.get('id');
this.artistService.getArtist(id).pipe(tap(artist => this.artistForm.setValue({ArtistName: artist.ArtistName}))).subscribe(artist => {
  artist = this.artist;
  });

}

现在是html:

   <h2>Artist Information</h2>
  <form [formGroup]="artistForm">
  <div class="form-group">
  <label class="center-block">Artist Name:

    <input class="form-control" formControlName="ArtistName">
  </label>
</div>