angular 2 remove todos os itens de um formarray

86

Eu tenho uma matriz de formulário dentro de um formbuilder e estou alterando formulários dinamicamente, ou seja, ao clicar em carregar dados do aplicativo 1 etc.

O problema que estou tendo é que todos os dados carregam, mas os dados no formarray permanecem e apenas concatam os itens antigos com os novos.

Como faço para limpar o formarray para ter apenas os novos itens.

Eu tentei isso

const control2 = <FormArray>this.registerForm.controls['other_Partners'];
        control2.setValue([]);

mas não funciona.

Alguma ideia? obrigado

em nginit

ngOnInit(): void {
this.route.params.subscribe(params => { alert(params['id']);
            if (params['id']) {
                this.id = Number.parseInt(params['id']);
            }
            else { this.id = null;}
          });
if (this.id != null && this.id != NaN) {
            alert(this.id);
            this.editApplication();
            this.getApplication(this.id);
        }
        else
        {
            this.newApplication();
        }

}

onSelect(Editedapplication: Application) {
 this.router.navigate(['/apply', Editedapplication.id]);
}

editApplication() {
      
        this.registerForm = this.formBuilder.group({
              id: null,
            type_of_proposal: ['', Validators.required],
            title: ['', [Validators.required, Validators.minLength(5)]],
            lead_teaching_fellow: ['', [Validators.required, Validators.minLength(5)]],
            description: ['', [Validators.required, Validators.minLength(5)]],
            status: '',
            userID: JSON.parse(localStorage.getItem('currentUser')).username,
            contactEmail: JSON.parse(localStorage.getItem('currentUser')).email,
            forename: JSON.parse(localStorage.getItem('currentUser')).firstname,
            surname: JSON.parse(localStorage.getItem('currentUser')).surname,
            line_manager_discussion: true,
            document_url: '',
            keywords: ['', [Validators.required, Validators.minLength(5)]],
            financial_Details: this.formBuilder.group({
                  id: null,
                buying_expertise_description: ['', [Validators.required, Validators.minLength(2)]],
                buying_expertise_cost: ['', [Validators.required]],
                buying_out_teaching_fellow_cost: ['', [Validators.required]],
                buying_out_teaching_fellow_desc: ['', [Validators.required, Validators.minLength(2)]],
                travel_desc: ['', [Validators.required, Validators.minLength(2)]],
                travel_cost: ['', [Validators.required]],
                conference_details_desc: ['', [Validators.required, Validators.minLength(2)]],
                conference_details_cost: ['', [Validators.required]],
            }),

            partners: this.formBuilder.array
                (
                [
                    //this.initEditPartner(),
                    //this.initEditPartner()
                    // this.initMultiplePartners(1)
                ]
                ),
            other_Partners: this.formBuilder.array([
                //this.initEditOther_Partners(),
            ])
           
        });
       
    }

getApplication(id)
    {
        

        this.applicationService.getAppById(id, JSON.parse(localStorage.getItem('currentUser')).username)
            .subscribe(Response => {
               
                    if (Response.json() == false) {
                        this.router.navigateByUrl('/');
                    }
                    else {
                        this.application = Response.json();  
                          for (var i = 0; i < this.application.partners.length;i++)
                          {
                                this.addPartner();
                          }
                          for (var i = 0; i < this.application.other_Partners.length; i++) {
                              this.addOther_Partner();
                          }

                          this.getDisabledStatus(Response.json().status);
                        (<FormGroup>this.registerForm)
                            .setValue(Response.json(), { onlySelf: true }); 
                      }

                }
         
        );

       
        
        

       
    }

ngonitit não está sendo chamado ao clicar

Karl O'Connor
fonte
Um problema relacionado é rastreado aqui no repositório Angular
E. Sundin,

Respostas:

145

Eu tive o mesmo problema. Existem duas maneiras de resolver esse problema.

Preservar assinatura

Você pode limpar manualmente cada elemento FormArray chamando a removeAt(i)função em um loop.

clearFormArray = (formArray: FormArray) => {
  while (formArray.length !== 0) {
    formArray.removeAt(0)
  }
}

A vantagem dessa abordagem é que nenhuma assinatura do seu formArray, como a registrada no formArray.valueChanges, será perdida.

Consulte a documentação do FormArray para obter mais informações.


Método mais limpo (mas quebra as referências de assinatura)

Você pode substituir FormArray inteiro por um novo.

clearFormArray = (formArray: FormArray) => {
  formArray = this.formBuilder.array([]);
}

Essa abordagem causa um problema se você estiver inscrito no formArray.valueChangesobservável! Se você substituir o FromArray por um novo array, perderá a referência ao observável ao qual está inscrito.

CamelD
fonte
67
A partir do Angular 8+, a maneira preferida de remover todos os componentes de um FormArray é usandoformArray.clear();
Renan
2
Além disso, yourFormArray.setValue ([])); e yourFormGroup.setControl ('yourFormArray', []);
Oscar
1
adeus validação com esta abordagem
Andre Elrico
@Renan Estou usando o formControl
Emir Herrera
29

Ou você pode simplesmente limpar os controles

this.myForm= {
     name: new FormControl(""),
     desc: new FormControl(""),
     arr: new FormArray([])
}

Adicionar algo array

const arr = <FormArray>this.myForm.controls.arr;
arr.push(new FormControl("X"));

Limpe a matriz

const arr = <FormArray>this.myForm.controls.arr;
arr.controls = [];

Quando você tem várias opções selecionadas e desmarcadas, às vezes não atualiza a visualização. Uma solução alternativa é adicionar

arr.removeAt(0)

ATUALIZAR

Uma solução mais elegante para usar matrizes de formulário é usar um getter no topo da sua classe e então você pode acessá-lo.

get inFormArray(): FormArray {
    this.myForm.get('inFormArray') as FormArray;
}

E para usá-lo em um modelo

<div *ngFor="let c of inFormArray; let i = index;" [formGroup]="i">
other tags...
</div>

Redefinir:

inFormArray.reset();

Empurrar:

inFormArray.push(new FormGroup({}));

Remova o valor do índice: 1

inFormArray.removeAt(1);

ATUALIZAÇÃO 2:

Obtenha objeto parcial, obtenha todos os erros como JSON e muitos outros recursos, use o NaoFormsModule

Pian0_M4n
fonte
5
O "arr.controls = [];" mencionar é realmente ótimo!
dotNetkow
@Pian, Only const arr = <FormArray> this.myForm.controls.arr; arr.controls = []; está trabalhando para limpar a matriz do formulário. TQ
chandoo
inFormArray.at(1).remove(); me dá um [ts] Property 'remove' does not exist on type 'AbstractControl'.erro de transpiler.
zgue
@ Pian0_M4n em seu modelo, let c of inFormArraydeveria let c of inFormArray.controls?
março,
22

A partir do Angular 8+, você pode usar clear()para remover todos os controles no FormArray:

const arr = new FormArray([
   new FormControl(),
   new FormControl()
]);
console.log(arr.length);  // 2

arr.clear();
console.log(arr.length);  // 0

Para versões anteriores, a forma recomendada é:

while (arr.length) {
   arr.removeAt(0);
}

https://angular.io/api/forms/FormArray#clear

crappylime
fonte
1
Obrigado por mencionar o Angular 8+ aqui.
Patrick Hillert
10

Angular 8

simplesmente use o clear()método em formArrays:

(this.invoiceForm.controls['other_Partners'] as FormArray).clear();
MajiD
fonte
8

Angular v4.4 se você precisar salvar a mesma referência para a instância do FormArray, tente o seguinte:

purgeForm(form: FormArray) {
  while (0 !== form.length) {
    form.removeAt(0);
  }
}
Alex Dzeiko
fonte
Uma boa maneira de preservar a assinatura enquanto retira elementos do array.
red_dorian
@mtpultz, observe o log de mudanças ( stackoverflow.com/posts/41856927/revisions ) da resposta aceita. No momento em que deixei essa resposta aceita foi diferente da atual.
Alex Dzeiko
8

Atenção!

A documentação do FormArray do Angular v6.1.7 diz:

Para alterar os controles na matriz, use os métodos push, insert ou removeAt no próprio FormArray. Esses métodos garantem que os controles sejam rastreados adequadamente na hierarquia do formulário. Não modifique a matriz de AbstractControls usada para instanciar o FormArray diretamente, pois isso resulta em um comportamento estranho e inesperado, como detecção de alteração interrompida.

Lembre-se disso se estiver usando a splicefunção diretamente na controlsmatriz como uma das respostas sugeridas.

Use a removeAtfunção.

  while (formArray.length !== 0) {
    formArray.removeAt(0)
  }
zgue
fonte
6

Você pode definir facilmente um getter para sua matriz e limpá-lo da seguinte maneira:

  formGroup: FormGroup    
  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    this.formGroup = this.fb.group({
      sliders: this.fb.array([])
    })
  }
  get sliderForms() {
    return this.formGroup.get('sliders') as FormArray
  }

  clearAll() {
    this.formGroup.reset()
    this.sliderForms.clear()
  }
M.Reza
fonte
Thx It works ......
nart
5

Atualização: o Angular 8 finalmente obteve o método para limpar o Array FormArray.clear ()

nightingale2k1
fonte
4

Desde Angular 8 você pode usar this.formArray.clear()para limpar todos os valores na matriz do formulário. É uma alternativa mais simples e eficiente para remover todos os elementos um por um

Nikita Korba
fonte
4

Use FormArray.clear () para remover todos os elementos de uma matriz em um FormArray

Anu Priya
fonte
3

Forneceu a estrutura de dados para o que você estará substituindo as informações no array com o que já está lá você pode usar patchValue

https://angular.io/docs/ts/latest/api/forms/index/FormArray-class.html#!#reset-anchor

patchValue (value: any [], {onlySelf, emitEvent} ?: {onlySelf ?: boolean, emitEvent ?: boolean}): void Corrige o valor do FormArray. Ele aceita uma matriz que corresponda à estrutura do controle e fará o possível para corresponder os valores aos controles corretos no grupo.

Ele aceita superconjuntos e subconjuntos da matriz sem gerar um erro.

const arr = new FormArray([
   new FormControl(),
   new FormControl()
]);
console.log(arr.value);   // [null, null]
arr.patchValue(['Nancy']);
console.log(arr.value);   // ['Nancy', null]

Alternativamente, você pode usar reset

reset (value ?: any, {onlySelf, emitEvent} ?: {onlySelf ?: boolean, emitEvent ?: boolean}): void Redefine o FormArray. Isso significa por padrão:

O array e todos os descendentes são marcados como prístinos O array e todos os descendentes são marcados como intocados O valor de todos os descendentes serão mapas nulos ou nulos Você tambémpoderá restabelecer para um estado de forma específico passando um array de estados que corresponde à estrutura do controle . O estado pode ser um valor autônomo ou um objeto de estado de formulário com um valor e um status desabilitado.

this.arr.reset(['name', 'last name']);
console.log(this.arr.value);  // ['name', 'last name']

OU

this.arr.reset([   {value: 'name', disabled: true},   'last' ]);
console.log(this.arr.value);  // ['name', 'last name']
console.log(this.arr.get(0).status);  // 'DISABLED'

Aqui está uma demonstração bifurcada do Plunker de algum trabalho anterior meu demonstrando uma utilização muito simples de cada um.

Silentsod
fonte
certamente isso significa que você deve ter exatamente o mesmo número de itens no array.
Simon_Weaver
2

Nunca tentei usar formArray, sempre trabalhei com FormGroup e você pode remover todos os controles usando:

Object.keys(this.formGroup.controls).forEach(key => {
          this.formGroup.removeControl(key);
        });

sendo formGroup uma instância de FormGroup.

Pianisimo
fonte
1

Estou muito atrasado, mas encontrei outra maneira em que você não precisa de loops. você pode redefinir o array definindo o controle do array como vazio.

O código abaixo irá redefinir sua matriz.

this.form.setControl('name', this.fb.array([]))

Até parece
fonte
0

O loop while levará muito tempo para excluir todos os itens se a matriz tiver 100 itens. Você pode esvaziar os controles e propriedades de valor do FormArray como abaixo.

clearFormArray = (formArray: FormArray) => {formArray.controls = []; formArray.setValue ([]); }

user3067875
fonte
0

Para manter o código limpo, criei o seguinte método de extensão para qualquer pessoa usando Angular 7 e inferior. Isso também pode ser usado para estender qualquer outra funcionalidade dos formulários reativos.

import { FormArray } from '@angular/forms';

declare module '@angular/forms/src/model' {
  interface FormArray {
    clearArray: () => FormArray;
  }
}

FormArray.prototype.clearArray = function () {
  const _self = this as FormArray;
  _self.controls = [];
  _self.setValue([]);
  _self.updateValueAndValidity();
  return _self;
}

Danielok 1993
fonte