Angular2 definir valor para formGroup

94

Portanto, tenho um formulário complexo para criar uma entidade e também quero usá-lo para edição. Estou usando a nova API de formulários angulares. Estruturei o formulário exatamente como os dados que recupero do banco de dados, portanto, quero definir o valor de todo o formulário para os dados recuperados. Aqui está um exemplo do que eu quero fazer:

this.form = builder.group({
      b : [ "", Validators.required ],
      c : [ "", Validators.required ],
      d : [ "" ],
      e : [ [] ],
      f : [ "" ]
    });
this.form.value({b:"data",c:"data",d:"data",e:["data1","data2"],f:data});

PS: NgModel não funciona com novas APIs de formulários, também não me importo de usar vinculação de dados unilateral no modelo como em

<input formControlName="d" value="[data.d]" />

isso funciona, mas seria uma dor no caso das matrizes

Amgad Serry
fonte
Pelo que eu sei, a definição de um valor de formulários não é compatível no momento e será compatível após a próxima atualização (RC.5). Forneça um Plunker.
Günter Zöchbauer
@ GünterZöchbauer verifique minha solução atual
Amgad Serry
Você olha para: github.com/angular/angular/blob/2.0.0-rc.5/modules/%40angular/… linha 553 FormGroup.setValue ()?
Clemente

Respostas:

305

Para definir todos os valores de FormGroup, use setValue :

this.myFormGroup.setValue({
  formControlName1: myValue1, 
  formControlName2: myValue2
});

Para definir apenas alguns valores, use patchValue :

this.myFormGroup.patchValue({
  formControlName1: myValue1, 
  // formControlName2: myValue2 (can be omitted)
});

Com esta segunda técnica, nem todos os valores precisam ser fornecidos e os campos cujos valores não foram definidos não serão afetados.

Stephen Paul
fonte
1
Estou usando patchValue em um formulário aninhado e ele está substituindo todos os campos do formulário. (mesmo aqueles que não especifico) alguma ideia do que estou fazendo de errado?
Enrico,
@Enrico, sem seu código não posso te ajudar.
manymanymore
10

Para definir o valor quando seu controle é FormGroup pode usar este exemplo

this.clientForm.controls['location'].setValue({
      latitude: position.coords.latitude,
      longitude: position.coords.longitude
    });
Sergiy Voytovych
fonte
6

Você pode usar form.get para obter o objeto de controle específico e usar setValue

this.form.get(<formControlName>).setValue(<newValue>);
Trabalho Varadhan
fonte
5

Sim, você pode usar setValue para definir o valor para fins de edição / atualização.

this.personalform.setValue({
      name: items.name,
      address: {
        city: items.address.city,
        country: items.address.country
      }
    });

Você pode consultar http://musttoknow.com/use-angular-reactive-form-addinsert-update-data-using-setvalue-setpatch/ para compreender como usar formulários reativos para adicionar / editar recurso usando setValue. Economizou meu tempo

Prashant M Bhavsar
fonte
3

Conforme apontado nos comentários, esse recurso não era compatível no momento em que esta pergunta foi feita. Este problema foi resolvido no angular 2 rc5

Amgad Serry
fonte
2

Eu implementei uma solução temporária até o formulário de suporte do angular2 updateValue

 initFormGroup(form: FormGroup, data: any) {
        for(var key in form.controls) {
          console.log(key);
          if(form.controls[key] instanceof FormControl) {
            if(data[key]){
              let control = <FormControl>form.controls[key];
              this.initFormControl(control,data[key]);
            }
          } else if(form.controls[key] instanceof FormGroup) {
            if(data[key]){
              this.initFormGroup(<FormGroup>form.controls[key],data[key]);
            }
          } else if(form.controls[key] instanceof FormArray) {
            var control = <FormArray>form.controls[key];
            if(data[key])
            this.initFormArray(control, data[key]);
          }
        }
      }
      initFormArray(array: FormArray, data: Array<any>){
    if(data.length>0){
      var clone = array.controls[0];
      array.removeAt(0);
      for(var idx in data) {
        array.push(_.cloneDeep(clone));
        if(clone instanceof FormGroup)
          this.initFormGroup(<FormGroup>array.controls[idx], data[idx]);
        else if(clone instanceof FormControl)
          this.initFormControl(<FormControl>array.controls[idx], data[idx]);
        else if(clone instanceof FormArray)
          this.initFormArray(<FormArray>array.controls[idx], data[idx]);
      }
    }
  }


initFormControl(control: FormControl, value:any){
    control.updateValue(value);
  }

uso:

this.initFormGroup(this.form, {b:"data",c:"data",d:"data",e:["data1","data2"],f:data});

nota: formulário e dados devem ter a mesma estrutura e eu usei lodash para deepcloning jQuery e outras bibliotecas podem fazer o mesmo

Amgad Serry
fonte
0

"NgModel não funciona com novas APIs de formulários".

Isso não é verdade. Você só precisa usá-lo corretamente. Se você estiver usando as formas reativas, o NgModel deve ser usado em conjunto com a diretiva reativa. Veja o exemplo na fonte .

/*
 * @Component({
 *      selector: "login-comp",
 *      directives: [REACTIVE_FORM_DIRECTIVES],
 *      template: `
 *        <form [formGroup]="myForm" (submit)='onLogIn()'>
 *          Login <input type='text' formControlName='login' [(ngModel)]="credentials.login">
 *          Password <input type='password' formControlName='password'
 *                          [(ngModel)]="credentials.password">
 *          <button type='submit'>Log in!</button>
 *        </form>
 *      `})
 * class LoginComp {
 *  credentials: {login:string, password:string};
 *  myForm = new FormGroup({
 *    login: new Control(this.credentials.login),
 *    password: new Control(this.credentials.password)
 *  });
 *
 *  onLogIn(): void {
 *    // this.credentials.login === "some login"
 *    // this.credentials.password === "some password"
 *  }
 * }
 */

Embora pareça com os comentários TODO , isso provavelmente será removido e substituído por uma API reativa.

// TODO(kara):  Replace ngModel with reactive API
@Input('ngModel') model: any;
Paul Samsotha
fonte
vindo do angular2 api docs seletor NgModel [ngModel]: not ([formControlName]): not ([formControl]) angular.io/docs/ts/latest/api/forms/index/… então mesmo que funcione agora será removido mais tarde, acho que implementarei um injetor de valor manual, pois será uma solução mais estável
Amgad Serry
@AmgadSerry que é para garantir que não interfira com esses componentes (no seletor). O FormControlNameadiciona explicitamente como um @Input(). Veja a fonte à qual vinculei. Se esses seletores de negação não estivessem lá, com o exemplo acima, um NgModel seria criado, o que você não quer.
Paul Samsotha
É um pouco confuso, mas é assim que é implementado. Para FormControlDirective( [formControl]) e FormControlName( formControlName), é assim que funciona. Se ngModelfor usado sem um desses, presume-se que você usará formas declarativas e NgModelserá criado um. Se o ngModelfor usado junto com uma das diretivas de forma reativa , essa diretiva de forma reativa tratará do modelo, não umNgModel
Paul Samsotha
oh, eu pensei que eles fizeram isso como um hack para habilitar o ngModel nessas duas diretivas apenas por enquanto e eles irão removê-lo mais tarde
Amgad Serry
verifique minha solução atual
Amgad Serry