9
respostas

FormControlName iterado ?

Pessoal minha dúvida é sobre um parametro que um elemento html 'input' chamado FormControlName possui, eu criei um input apenas dentro de um span porém ele é iterado e não consigo criar dinamicamente um falor específico para cada um:

<tr *ngFor="let obj of list">
                <td *ngFor="let f of fields">
                    <span *ngIf="f['format'] == 'currency'">{{ getShowValue(obj, f['name']) | currency:'BRL':true }}</span>
                    <span *ngIf="f['format'] == 'date'">{{ getShowValue(obj, f['name']) | date:'dd/MM/yyyy' }}</span>
                    <span *ngIf="f['format'] == 'status'">{{ getShowValue(obj, f['name']) === 'A' ? 'Ativo' : 'Inativo' }}</span>
                    <span *ngIf="f['format'] == 'editable'">
                        <input type="text" class="form-control" value="{{ getShowValue(obj, f['name']) }}">   
                    </span>
                    <span *ngIf="!f['format']">{{ getShowValue(obj, f) || getShowValue(obj, f['name']) }}</span>
                </td> 
            </tr>
9 respostas

Olá, Rafael, como vai? Eu nunca tinha visto formulários dinâmicos dessa maneira e não sei se entendi a pergunta completamente, mas acredito que você pode colocar o nome do formControlName como atributo do objeto que você está iterando.

Mais ou menos assim:

<tr *ngFor="let obj of list">
    <td *ngFor="let f of fields">
        (...)
        <span *ngIf="f['format'] == 'editable'">
            <input type="text" formControlName="{{obj.nomeCampo}}" class="form-control" value="{{ getShowValue(obj, f['name']) }}" >   
        </span>

    </td> 
</tr>

Você só vai precisar garantir que existam os FormControls no seu component.

Bom dia Vínicius, primeiramente obrigado por me ajudar, é o seguinte:

Esse código abaixo é o meu componente, eu tenho um Grid com duas colunas uma chamada de Parametro e a outra de Valor, na coluna valor eu tenho um input para cada registro, o que preciso fazer é editar os valores que estão nesses inputs e salvar, porém não sei como proceder, voce pode me ajudar?

import { Component, OnInit, OnDestroy, Inject, ElementRef, ViewChildren, AfterViewInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { FormBuilder, FormGroup, Validators, FormControlName, FormControl, FormArray } from '@angular/forms';
import { BasicValidators } from 'app/shared/basic-validator';
import { GenericValidator } from 'app/shared/generic-validator';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from 'app/repositories/httpClient';
import { BaseValidatorComponent } from 'app/controllers/common/base-validator.component';
import { DocumentosValidator } from 'app/shared/validators/documentos.validator';
import { GenericServiceFactory } from 'app/repositories/common/generic-service-factory.service';
import { GenericService } from 'app/repositories/common/generic.service';
import { IError } from 'app/model/error.model';
import { ToastsManager } from 'ng2-toastr';
import { GenericDataService } from 'app/repositories/generic-data.service';
import { IParametro } from 'app/model/parametro.model';

@Component({
    templateUrl: '../../../views/common/inline-edit.component.html'
})
export class ParametroEditComponent extends BaseValidatorComponent implements OnInit {
    form: FormGroup;
    formListArray:FormArray;

    id: number
    title: string;
    parametro: IParametro

    salvando: boolean

    service: GenericService<IParametro>

    constructor(private route: ActivatedRoute,
        private fb: FormBuilder,
        private serviceFactory: GenericServiceFactory,
        private dataService: GenericDataService,
        private toastr: ToastsManager,
        private router: Router,
        private http: HttpClient) {
        super();

        this.service = serviceFactory.createHttpServiceFor<IParametro>('parametro');

        this.form = fb.group({
            paramList:this.fb.array([
                this.fb.group({
                    parametroValor:this.fb.control(null),
                }),
            ]),
        });

        this.formListArray = this.form.get('paramList') as FormArray;
    }

    save() {
        const parametro = <IParametro>this.form.value;
        this.salvando = true;
        if (!this.id || this.id === 0) {
            this.salvarNovo(parametro);
        } else {
            this.atualizar();
        }
    }

    salvarNovo(parametro: IParametro) {
        this.service.post(parametro)
        .catch((err: IError) => {
            this.salvando = false;
            this.toastr.error(err.message, 'Criação de Parametro');
            return Observable.throw(err);
        })
        .subscribe((result) => {
            this.toastr.success('Parametro criado com sucesso', 'Criação de parametro');
            this.router.navigateByUrl('/configuracoes/parametro');
        });
    }

    atualizar() {
        this.service.putWithoutId(null)
            .catch((err: IError) => {
                this.salvando = false;
                this.toastr.error(err.message, 'Atualização de parmetro');
                return Observable.throw(err);
            })
            .subscribe((result) => {
                this.toastr.success('Parâmetro atualizado com sucesso', 'Atualização de parâmetro');
                this.router.navigateByUrl('/configuracoes/parametro');
            });
    }

    getValidationMessages(): { [key: string]: { [key: string]: string; }; } {
        return {
            parametroValor: {
                required: 'Campo Valor é obrigatório'
            },
        }
    }

    async ngOnInit() {
        this.route.params.subscribe(params => {
            this.id = +params['id'];
            this.title = 'Incluir Parâmetro';
            if (this.id && this.id !== 0) {
                this.title = 'Alterar Parâmetro'
                this.service.getById(this.id)
                .subscribe(data => {
                    this.form.patchValue({
                        parametroValor: data.parametroValor
                    });
                });
            }
        });
    }

}

Rafael, como vai?

Você está iterando uma lista de IParametro, certo? Cada IParametro é um parâmetro que você quer alterar, certo?

Você pode referenciar o nome do campo no IParametro no atributo formControlName do seu html.

Você só precisa garantir que seu form vai ter os mesmos identificadores da sua lista de IParametro.

Estou utilizando dessa forma pra referenciar os meus campos, mas lembrando que apenas o campo parametroValor é editado, estou usando um formGroup que recebe um formArray e nesse formArray existem os campos do meu form, que alias é dentro da própria tabela.Voce poderia me dar um exemplo Vinicius? é muito importante..Não sei se ficou claro.

 this.form = fb.group({
            paramList:this.fb.array([{
                parametroNome: this.fb.control(['', Validators.required]),
                parametroValor:this.fb.control(['', Validators.required])  
            }]),
        });

        this.formListArray = this.form.get('paramList') as FormArray;

Existe um exemplo que achei na internet, estava tentando segui-lo mas ainda existe um erro de "TypeError: Cannot read property 'get' of undefined"

 <table formArrayName="salesList">
                                    <tr>
                                     <th>Item Detail</th>
                                     <th>Quantity</th>
                                     <th>Rate</th>
                                     <th>Tax</th>
                                     <th>Amount</th>
                                    </tr>
                                    <!--Input controls -->
                                    <tr  *ngFor="let saleList of salesListArray.controls;let i = index" [formGroupName]="i">
                                        <td>
                                             <div class="col-sm-6">
                                                 <input class="form-control" type="text" placeholder="Item Detail" formControlName = "itemDetail"/>
                                             </div>
                                        </td>
                                         <td>
                                             <div class="col-sm-6">
                                                 <input class="form-control" type="text"   placeholder="0" formControlName = "quantity" />
                                             </div>
                                        </td>
                                         <td>
                                             <div class="col-sm-6">
                                                 <input class="form-control" type="text"   placeholder="0.00" formControlName = "rate"/>
                                             </div>
                                        </td>
                                         <td>
                                             <div class="col-sm-6">
                                                 <input class="form-control" type="text"   placeholder="Select a tax" formControlName = "tax"/>
                                             </div>
                                        </td>
                                         <td>
                                             <div class="col-sm-6">
                                                <span>{{saleList.amount}}}</span>
                                             </div>
                                        </td>
                                    </tr>
                                </table>

Rafael, Não entendi a real necessidade de usar o método array do FormBuilder. Achei que os campos do formulário fossem dinâmicos. Mas parece que não são. Nesse caso, você pode declarar os campos do seu form direto no método "group", não precisa do formArray, mais ou menos assim:

this.form = fb.group({
    parametroNome: this.fb.control(['', Validators.required]),
    parametroValor:this.fb.control(['', Validators.required])
})

Se você sabe quantos e quais são os campos do seu form, monte a <table> de forma estática.

Rafael,

De qualquer modo, caso você realmente tenha uma lista de formGroups a iterar, tem um exemplo passo a passo na documentação do próprio Angular: https://angular.io/guide/reactive-forms#use-formarray-to-present-an-array-of-formgroups

Eles são dinâmicos Vinicius, deixa eu tentar explicar melhor, é assim:

  • Eu não tenho um formulário para cadastro, porque eu cadastro eles direto pelo banco mesmo,

  • cada insert que dou no banco ele inclui na tabela certo?, então cada registro tem um input no campo valor, esse input já vem preenchido com dados do banco.

  • A minha dúvida é saber se quando eu der o update ele vai saber de qual registro ele deve atualizar o valor, pois os inputs estão abertos mesmo, o formArray era pra tentar dar um id diferente ou sei lá, para cada registro cadastrado.

  • Tendo em vista que possue apenas um input no html, então sim ele é dinâmico.

É confuso eu sei kkkkk

<tr *ngFor="let obj of list">
    <td *ngFor="let f of fields">
        (...)
        <span *ngIf="f['format'] == 'editable'">
            <input type="text" formControlName="{{obj.nomeCampo}}" class="form-control" value="{{ getShowValue(obj, f['name']) }}" >   
        </span>

    </td> 
</tr>

Olhando o seu código abaixo:


 this.form = fb.group({
            paramList:this.fb.array([{
                parametroNome: this.fb.control(['', Validators.required]),
                parametroValor:this.fb.control(['', Validators.required])  
            }]),
        });

        this.formListArray = this.form.get('paramList') as FormArray;

Falta declarar o "control"

let seuArray = this.fb.array([{
    parametroNome: this.fb.control(['', Validators.required]),
    parametroValor:this.fb.control(['', Validators.required])  
}])
 this.form = fb.group({
    paramList: seuArray
});
this.form.setControl('paramList', seuArray); // <-- Declarando o control para o form
this.formListArray = this.form.get('paramList') as FormArray; // <-- Agora sim esse get funciona