• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Zduplikowane dane w inputach w formularzu angular

VPS Starter Arubacloud
+1 głos
65 wizyt
pytanie zadane 25 kwietnia 2023 w HTML i CSS przez TheDarkSide Użytkownik (930 p.)

Kod html:

<form method="POST" [formGroup]="addInvoiceForm" (ngSubmit)="addData()">
  <div class="formularz" *ngFor="let item of items">
    <mat-form-field >
      <mat-label>Name</mat-label>
      <input type="text" matInput formControlName="name"   maxlength="30" minlength="3" required>
      <mat-error *ngIf="addInvoiceF['name'].errors && addInvoiceF['name'].errors['required']">Name is required</mat-error>
    </mat-form-field>
    <mat-form-field>
      <mat-label>Count</mat-label>
      <input type="number"  formControlName="count" matInput  maxlength="100" minlength="1">
    </mat-form-field>
    <mat-form-field >
      <mat-label>Price</mat-label>
      <input type="number" matInput formControlName="price"  maxlength="1000000" minlength="1" required>
      <mat-error *ngIf="addInvoiceF['price'].errors && addInvoiceF['price'].errors['required']">Price is required</mat-error>
    </mat-form-field>
    <button mat-icon-button color="primary" class="delete" matTooltip="Remove item" (click)="deleteForm(item)">
      <mat-icon>delete</mat-icon>
    </button>
  </div>
  <div class="add-new">
    <button type="button" mat-icon-button color="primary" class="add" matTooltip="Add new item" (click)="addForm()">
      <mat-icon>add</mat-icon>
      Add new item
    </button>
  </div>
  <div class="add">
    <button mat-icon-button color="primary" class="myButton" id="add_data_button">
      Submit
    </button>
  </div>
</form>

Typescript: 

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroupDirective, NgForm, Validators, FormBuilder, FormGroup } from '@angular/forms';
import { ViewChild, ElementRef } from '@angular/core';
import { PagesService } from '../pages.service';
import { Router } from '@angular/router';

@Component({
  selector: 'app-new-invoice',
  templateUrl: './new-invoice.component.html',
  styleUrls: ['./new-invoice.component.css']
})
export class NewInvoiceComponent implements OnInit {

  addInvoiceForm!: FormGroup;
  get addInvoiceF() { return this.addInvoiceForm.controls; }

  items: any[] = [
    { form: new FormGroup({
        name: new FormControl('', Validators.required),
        count: new FormControl('', Validators.required),
        price: new FormControl('', Validators.required)
      })
    }
  ];

  formRows: any[] = [{ name: '', count: 1, price: '' }];

  constructor(
    private formBuilder: FormBuilder,
    private pagesService: PagesService,
    private router: Router
  ) {
    window.addEventListener('beforeunload', () => {
      for (let key in localStorage) {
        if (key.includes('formRows')) {
          localStorage.removeItem(key);
        }
      }
    });
  }


  ngOnInit(): void {
    this.addInvoiceForm = this.formBuilder.group({
      name: ['', Validators.required],
      count: ['', ],
      price: ['', Validators.required],
    });
  }

  addFormRow() {
    this.formRows.push({ name: '', count: 1, price: '' });
  }

  addForm() {
    const newForm = {
      form: new FormGroup({
        name: new FormControl('', Validators.required),
        count: new FormControl('', Validators.required),
        price: new FormControl('', Validators.required)
      })
    };
    this.items.push(newForm);
  }

  deleteForm(item: any) {
    const index = this.items.indexOf(item);
    if (index !== -1) {
      this.items.splice(index, 1);
    }
  }

  addData() {
    if (this.addInvoiceForm.invalid) {
      return;
    }
    
    const formRows = this.items.map(item => ({
      name: this.addInvoiceF['name'].value || '',
      count: this.addInvoiceF['count'].value || '',
      price: this.addInvoiceF['price'].value || '' 
    }));
    
    this.pagesService.setFormData(formRows);
    
    console.log(formRows);
    
    this.router.navigate(['/preview-invoice']);
  }
}

Dane normalnie się dodają ale po kliknięciu add new item i wielu inputach dane które są wpisywane są powielone. Zostają przesyłane poprawnie ale wszyskie sa takie same.

1 odpowiedź

+1 głos
odpowiedź 25 kwietnia 2023 przez Wiciorny Ekspert (269,120 p.)
edycja 25 kwietnia 2023 przez Wiciorny

Sprawdź dokładnie działanie tego mapowania dla this.items.
 

const formRows = this.items.map(item => ({
      name: this.addInvoiceF['name'].value || '',
      count: this.addInvoiceF['count'].value || '',
      price: this.addInvoiceF['price'].value || '' 
    }));

Mapujesz obiekt item, który to wygląda troche inaczej niż przekazany tutaj, gdyż tablica item, zawiera obiekt, którego kluczem jest form: a wartościa jest  FormGroup  u Ciebie
 

new FormGroup({
        name: new FormControl('', Validators.required),
        count: new FormControl('', Validators.required),
        price: new FormControl('', Validators.required)
      }

Idąc tym tokiem myślenia: Zwrócone przez to mapowanie będą trzy wartości: name, count i price, każda z nich to wartość pola formularza lub pusty łańcuch, jeśli pole jest puste, w tym wypadku  otrzymasz tablicę z nowymi obiektami, z których każdy będzie zawierał te trzy wartości.

Jeśli używasz tego samego mapowania dla wielu elementów, dla przypadku, który umieściłeś wcześniej, to tak, dane będą się duplikować dla każdego elementu mapowanego.

Kazdy element, zawsze otrzymuje to samo praktycznie ... wartośc dla this.addInvoiceF['klucz'];

this.addInvoiceF['name']


Więc jeśli tablica ITEMS - ma 3 elementy aktualnie, to wszystkie poprzednie elementy podczas addData() funkcji będą otrzymywać wartości tego samego formularza this.addInvoiceF

Wydaje mi się ,że możesz to zrobić zmieniając nie co mapowanie, na wykorzystanie indeksu 

this.items.map((item, index) => ({
  name: this.items[index].form.controls.name.value || '',
  count: this.items[index].form.controls.count.value || '',
  price: this.items[index].form.controls.price.value || '' 
}));

wtedy uzyskasz odpowiedni formularz dla każdego elementu, dzięki czemu każdy element nowej tablicy będzie zawierał inne wartości, które są aktualnie wprowadzone w polach formularza.
Tylko musisz w takim razie jakos dostosować this.items[index - do formularza który aktualnie masz this.addInvoiceF, albo aktualizować TYLKO OSTATNI element z tablicy items, a nie wszystkie tymi samymi danymi 

komentarz 26 kwietnia 2023 przez TheDarkSide Użytkownik (930 p.)

Dziękuję za odpowiedź. Trochę w międzyczasie zmodyfikowałam mój kod teraz wygląda tak : 

 <form method="POST" [formGroup]="addInvoiceForm" (ngSubmit)="addData()">
  <div class="formularz" *ngFor="let item of items">
    <mat-form-field >
      <mat-label>Name</mat-label>
      <input type="text" matInput formControlName="name"   maxlength="30" minlength="3"required>
      <mat-error *ngIf="addInvoiceF['name'].errors && addInvoiceF['name'].errors['required']">Name is required</mat-error>
    </mat-form-field>
    <mat-form-field>
      <mat-label>Count</mat-label>
      <input type="number"  formControlName="count" matInput  maxlength="100" minlength="1">
    </mat-form-field>
    <mat-form-field >
      <mat-label>Price</mat-label>
      <input type="number" matInput formControlName="price"  maxlength="1000000" minlength="1" required>
      <mat-error *ngIf="addInvoiceF['price'].errors && addInvoiceF['price'].errors['required']">Price is required</mat-error>
    </mat-form-field>
    <button mat-icon-button color="primary" class="delete" matTooltip="Remove item" (click)="deleteForm(item)">
      <mat-icon>delete</mat-icon>
    </button>
  </div>
  <div class="add-new">
    <button type="button" mat-icon-button color="primary" class="add" matTooltip="Add new item" (click)="addForm()">
      <mat-icon>add</mat-icon>
      Add new item
    </button>
  </div>
  <div class="add">
    <button mat-icon-button color="primary" class="myButton" id="add_data_button">
      Submit
    </button>
  </div>
</form>

I tak : 



 <form method="POST" [formGroup]="addInvoiceForm" (ngSubmit)="addData()">
  <div class="formularz" *ngFor="let item of items">
    <mat-form-field >
      <mat-label>Name</mat-label>
      <input type="text" matInput formControlName="name"   maxlength="30" minlength="3"required>
      <mat-error *ngIf="addInvoiceF['name'].errors && addInvoiceF['name'].errors['required']">Name is required</mat-error>
    </mat-form-field>
    <mat-form-field>
      <mat-label>Count</mat-label>
      <input type="number"  formControlName="count" matInput  maxlength="100" minlength="1">
    </mat-form-field>
    <mat-form-field >
      <mat-label>Price</mat-label>
      <input type="number" matInput formControlName="price"  maxlength="1000000" minlength="1" required>
      <mat-error *ngIf="addInvoiceF['price'].errors && addInvoiceF['price'].errors['required']">Price is required</mat-error>
    </mat-form-field>
    <button mat-icon-button color="primary" class="delete" matTooltip="Remove item" (click)="deleteForm(item)">
      <mat-icon>delete</mat-icon>
    </button>
  </div>
  <div class="add-new">
    <button type="button" mat-icon-button color="primary" class="add" matTooltip="Add new item" (click)="addForm()">
      <mat-icon>add</mat-icon>
      Add new item
    </button>
  </div>
  <div class="add">
    <button mat-icon-button color="primary" class="myButton" id="add_data_button">
      Submit
    </button>
  </div>
</form>
and my Typescript:

   `import { Component, OnInit } from '@angular/core';
    import { FormControl, FormGroupDirective, NgForm, Validators, FormBuilder, FormGroup } from '@angular/forms';
    import { ViewChild, ElementRef } from '@angular/core';
    import { PagesService } from '../pages.service';
    import { Router } from '@angular/router';
    
    @Component({
      selector: 'app-new-invoice',
      templateUrl: './new-invoice.component.html',
      styleUrls: ['./new-invoice.component.css']
    })
    export class NewInvoiceComponent implements OnInit {
    
      addInvoiceForm!: FormGroup;
      get addInvoiceF() { return this.addInvoiceForm.controls; }
    
      items: any[] = [
        { form: new FormGroup({
            name: new FormControl('', Validators.required),
            count: new FormControl('', Validators.required),
            price: new FormControl('', Validators.required)
          })
        }
      ];
    
      formRows: any[] = [{ name: '', count: 1, price: '' }];
    
      constructor(
        private formBuilder: FormBuilder,
        private pagesService: PagesService,
        private router: Router
      ) {
        window.addEventListener('beforeunload', () => {
          for (let key in localStorage) {
            if (key.includes('formRows')) {
              localStorage.removeItem(key);
            }
          }
        });
      }
    
    
      ngOnInit(): void {
        this.addInvoiceForm = this.formBuilder.group({
          name: ['', Validators.required],
          count: ['', ],
          price: ['', Validators.required],
        });
      }
    
      addFormRow() {
        this.formRows.push({ name: '', count: 1, price: '' });
      }
    
      addForm() {
        const newForm = {
          form: new FormGroup({
            name: new FormControl('', Validators.required),
            count: new FormControl('', Validators.required),
            price: new FormControl('', Validators.required)
          })
        };
        this.items.push(newForm);
      }
    
      deleteForm(item: any) {
        const index = this.items.indexOf(item);
        if (index !== -1) {
          this.items.splice(index, 1);
        }
      }
    
      addData() {
  if (this.addInvoiceForm.invalid) {
    return;
  }

  const formRows = this.items.map(item => ({
    name: item.form.value.name || '',
    count: item.form.value.count || '',
    price: item.form.value.price || '' 
  }));
  
  formRows.push({
    name: this.addInvoiceForm.value.name || '',
    count: this.addInvoiceForm.value.count || '',
    price: this.addInvoiceForm.value.price || '' 
  });
  
  this.pagesService.setFormData(formRows);
  
  console.log(formRows);
  
  this.router.navigate(['/preview-invoice']);
}
    }

Teraz z kolei w konsoli wyświetla mi tylko ostatnią wpisana wartość z inputów. Np po stworzeniu trzech formularzy przez add new Item po submicie zapisuje tylko dane z tego ostatniego wiersza z inputami. 

Podobne pytania

0 głosów
1 odpowiedź 254 wizyt
pytanie zadane 25 czerwca 2019 w JavaScript przez sapero Gaduła (4,100 p.)
0 głosów
2 odpowiedzi 173 wizyt
pytanie zadane 8 czerwca 2023 w HTML i CSS przez TheDarkSide Użytkownik (930 p.)

92,453 zapytań

141,262 odpowiedzi

319,088 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...