如何在Angular中的响应式表单中设置表单控件的值

123

我是Angular的新手。实际上,我正在尝试从服务订阅数据,并将这些数据传递到我的表单控件中,例如编辑表单。

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators, FormArray, FormControl } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { QuestionService } from '../shared/question.service';

@Component({
  selector: 'app-update-que',
  templateUrl: './update-que.component.html',
  styleUrls: ['./update-que.component.scss']
})
export class UpdateQueComponent implements OnInit {

  questionsTypes = ['Text Type', 'Multiple choice', 'Single Select'];
  selectedQuestionType: string = "";
  question: any = {};

  constructor(private route: ActivatedRoute, private router: Router,
    private qService: QuestionService, private fb: FormBuilder) { 

  }

  ngOnInit() {
      this.getQuebyid();
  }

  getQuebyid(){
    this.route.params.subscribe(params => {
      this.qService.editQue([params['id']]).subscribe(res =>{
        this.question = res;
      });
    });
  }

  editqueForm =  this.fb.group({
    user: [''],
    questioning: ['', Validators.required],
    questionType: ['', Validators.required],
    options: new FormArray([])
  })

  setValue(){
    this.editqueForm.setValue({user: this.question.user, questioning: this.question.questioning})
  }

}

如果我在表单字段上使用[(ngModule)]来设置元素的值,它可以正常工作,但会显示一个警告,即在Angular 7版本中它将被弃用。

如果我在我的表单字段上使用[(ngModule)]来设置值到我的元素上,目前可以正常工作。但是在Angular 7版本中会有一个警告提示说这个语法将被废弃。

<textarea formControlName="questioning" [(ngModule)]="question.questioning" cols="70" rows="4"></textarea>

所以,我通过以下方式将值设置为我的表单控件,但该元素并未显示这些值。

setValue(){
   this.editqueForm.setValue({user: this.question.user, questioning: this.question.questioning})
}

有人能告诉我如何为我的响应式表单设置值吗?

5个回答

186

在响应式表单中设置或更新表单控件的值可以使用patchValue和setValue。然而,在某些情况下,使用patchValue可能会更好。

patchValue不需要在参数中指定所有控件就能更新/设置表单控件的值。另一方面,setValue需要填写所有表单控件的值,如果参数未指定任何一个控件,则它将返回错误。

在这种情况下,我们将使用patchValue,因为我们只更新userquestioning

this.qService.editQue([params["id"]]).subscribe(res => {
  this.question = res;
  this.editqueForm.patchValue({
    user: this.question.user,
    questioning: this.question.questioning
  });
});

编辑:如果你想尝试一些ES6的对象解构,你可能更喜欢这样做。

const { user, questioning } = this.question;

this.editqueForm.patchValue({
  user,
  questioning
});

瞧!


1
请问您能否分享一下setValuepatchValue的区别以及为什么在这种情况下会起作用的细节。 - Sachin Gupta
1
是的,我实际上已经包含了它。对于我最初的编辑不够明确,我感到抱歉。 - wentjun
嗨@wentjun,它不起作用。我的表格仍然是空的,没有显示数据。 - sun
谢谢你救了我的一天,这帮我减少了很多代码。干杯 :) - Kedar Km
@SachinGupta,https://sc-consulting.medium.com/setvalue-vs-patchvalue-angular-a64a55e912b8 - Janatbek Orozaly
显示剩余3条评论

103

在响应式表单中,有两种主要的解决方案可以更新表单字段的值。

setValue:

  • 在构造函数中初始化模型结构

this.newForm = this.formBuilder.group({  
   firstName: ['', [Validators.required, Validators.minLength(3), Validators.maxLength(8)]],
   lastName: ['', [Validators.required, Validators.minLength(3), Validators.maxLength(8)]]
});
  • 如果您想更新表单的所有字段:

    this.newForm.setValue({
       firstName: 'abc',
       lastName: 'def'
    });
    
  • 如果您想更新表单的特定字段:

  • this.newForm.controls.firstName.setValue('abc');
    

    注意: 在 FormGroup 中,对于所有表单字段控件,提供完整的模型结构是必需的。如果您遗漏了任何属性或子集集合,那么它将抛出异常。

    patchValue:

    • 如果您想要更新表单中的一些特定字段:

    this.newForm.patchValue({
       firstName: 'abc'
    });
    

    注意:在 FormGroup 内,不必为所有或任何表单字段控件提供模型结构。如果您错过了任何属性或子集集合,则不会引发任何异常。


    在第三点中应该更正为,如果您想要更新表单的特定字段:this.newForm.controls.firstName.setValue('abc'); - devan

    10

    试试这个。

    editqueForm =  this.fb.group({
       user: [this.question.user],
       questioning: [this.question.questioning, Validators.required],
       questionType: [this.question.questionType, Validators.required],
       options: new FormArray([])
    })
    

    setValue()和patchValue()

    如果您想设置一个控件的值,仅设置其中一个控件的值将不起作用,因此您必须同时设置两个控件的值:

    formgroup.setValue({name: ‘abc’, age: ‘25’});
    

    在方法内部提及所有控件是必要的。如果不这样做,就会抛出错误。

    另一方面,patchvalue() 在这方面要容易得多,比如说你只想将名称分配为一个新值:

    formgroup.patchValue({name:’abc’});
    

    TAB键无法正常工作,当定义editqueForm时,“this.question”没有值。 - Eliseo
    我已经在我的订阅者中完成了它:ngAfterViewInit():void { this.childDetailDS$ .subscribe((data)= > { this.gDetailDS = data; cityPlaceForm = this.formBuilder.group({ cpCode:[this.gDetailDS.cpCode,Validators.required], cpName:[this.gDetailDS.cpName,Validators.required], province:[this.gDetailDS.province], status:[this.gDetailDS.status], versionNo:[this.gDetailDS.versionNo] }); }); - TAB
    不使用 ngAfterViewInit -是的,你不知道在 ngAfterViewInit 中是否有值-,你必须在“subscribe”中创建表单,请参考我的答案。 - Eliseo

    5
    “通常”的解决方案是创建一个函数,返回一个空的formGroup或已填充的formGroup。”
    createFormGroup(data:any)
    {
     return this.fb.group({
       user: [data?data.user:null],
       questioning: [data?data.questioning:null, Validators.required],
       questionType: [data?data.questionType, Validators.required],
       options: new FormArray([this.createArray(data?data.options:null])
    })
    }
    
    //return an array of formGroup
    createArray(data:any[]|null):FormGroup[]
    {
       return data.map(x=>this.fb.group({
            ....
       })
    }
    

    然后,在SUBSCRIBE中调用该函数。
    this.qService.editQue([params["id"]]).subscribe(res => {
      this.editqueForm = this.createFormGroup(res);
    });
    

    小心!你的表单必须包含*ngIf以避免初始错误。

    <form *ngIf="editqueForm" [formGroup]="editqueForm">
       ....
    </form>
    

    2

    要为单个表单控件分配值,我建议使用以下方式的setValue

    this.editqueForm.get('user').setValue(this.question.user);
    
    this.editqueForm.get('questioning').setValue(this.question.questioning);
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接