Angular-kafelki z formularzem

0

Hej uczę się Angulara 2 i staram się stworzyć kafelki z formularzem:
1.mam jedno pole "IMIE" i przycisk "DODAJ"
KAFELEK
1.1. po wypełnieniu pola i wciśnięciu przycisku "DODAJ" pojawia się kafelek z wyświetlonym imieniem z pola "IMIE" na górze, polem "WARTOŚĆ" i przyciskiem "DODAJ WARTOŚĆ"
1.2 Po wypełnieniu pola i wciśnięciu przycisku "DODAJ WARTOŚĆ" pojawia się pod spodem tabela w której wierszach wyświetlają się wpisane wartości
1.3 wartości może być dowolna ilość, można je też usuwać krzyżykiem, jak i też usunąć cały kafelek też w ten sposób.

kafelków może być max 10
w efekcie chciałbym przeslac jsona na backend np.
value:[{"name":"Janek", "value":[34,56,78,90]}, {"name":"Michal", "value":[30,15,3,7]}, {"name":"Kamil", "value":[33,56,78,99]}]

Czy ktoś ma jakiś pomysł jak to sprawnie zrobić albo jakiś tutorial pokazujący jak zagnieździć array value w array kafelka.
Zacząłem to robić na zasadzie Dynamic reactive form i umiem sobie dodać kafelek z polem i przyciskem, ale nie wiem jak ładować te wartości z kafelka do kolejnej tablicy. No i nie wiem, czy to podejście w tym przypadku jest dobre.

0
  1. W templatce html powinieneś wyświetlić pole z przyciskiem DODAJ WARTOŚĆ
  2. po wciśnięciu DODAJ WARTOŚĆ powinieneś wysłać formularz który by dodawał nową wartość w komponencie do tablicy: names[] (imię + inne wartości)
  3. do końca nie wiem czym są "value":[30,15,3,7] i skąd się biorą?
  4. pod przyciskiem w templatce powinna być wyświetlana wartość całej tablicy names[], przy użyciu ngFor, odpowiednio sformatowana
  5. do końca nie wiem jak bindować przycisk krzyżyka - iksa, ale to jest kwestia wygooglowania jak wysłać za pomocą tego przycisku (iksa) id/numer obiektu z tablicy
  6. iks/krzyżyk będzie uruchamiał funkcję/wysyłał formularz w komponencie, który usunie obiekt z tablicy names[]
0

Jeżeli potrzebujesz wyświetlić FormControl które są osadzone w FormArray, to możesz bez problemu skorzystać z FormArray.controls i przeiterować po nich ngForem. Jeżeli potrzebujesz to tylko wyświetlić w postaci tabelki bez możliwości edycji, możesz skorzystać z FormArray.value. Dodawać FormControl do FormArray możesz za pomocą FormArray.push (tutaj jednak polecam pushować jakikolwiek AbstractFormControl zamiast raw objecta). Do usuwania masz metodę FormArray.removeAt. Indeks elementu możesz dostać dodając w ngFor let i = index jako drugą instrukcję. Do obsługi eventu submit, możesz dodać w form podpinasz metodę pod (ngSubmit).

0

Hej może lepiej pokaże kawałek kodu.
Obecnie się męcze z wyciągnieciem wartości z payerName.

export class BillsComponent implements OnInit {
  payersGroup: FormGroup;
  constructor(private fb: FormBuilder) {
  }

  ngOnInit(): void {
    this.payersGroup = this.fb.group({
      payers: this.fb.array([])
    });
  }

  addPayersButtonClick(name: string): void {
    (this.payersGroup.get('payers') as FormArray)
      .push(this.createPayerFormGroup(name));
  }

  createPayerFormGroup(name: string): FormGroup {
    return this.fb.group({
      payerName: name,
      value: ['']
    });
  }
}

Więc mam payersGroup w którym mam tablicę payers przechowująca FormGroup z wartościami payerName i value . Grupa tworzona jest przez funkcję createPayerFormGroup.
Po dodaniu wartości payerName nie wiem jak ją wyciągnąć. Juz kombinowalem na różne sposoby ale coś mi nie idzie.

0

Albo wyciągasz to za pomocą FormGroup.value co w Twoim przypadku zwróci Ci obiekt typu{prayerName: string, value: string[]} i iterujesz po tym jak po zwykłej tablicy - tylko to Ci wtedy zwraca tablicę obiektów, nie FormGroup, albo korzystasz z FormArray.controls i to zwraca Ci wtedy AbstractControl[], gdzie już możesz sobie potem na odpowiednim z tych obiektów pobrać sobie value za pomocą FormGroup.value - i wtedy masz już pojedynczy obiekt. W zależności czy potrzebujesz to tylko wyświetlić value czy potrzebujesz mieć jednak podpięte kontrolki, jeżeli to pierwsze możesz wykorzystać FormArray.value, jeżeli to drugie to raczej musisz przeiterować po FormArray.controls. Wyciągnąć AbstractControl (wszystkie FormControl, FormGroup, FormArray dziedziczą po AbstractControl) z FormGroup możesz albo korzystając z metody FormGroup.get('prayerName') albo FormGroup.controls.prayerName.

0

hej sorki że dopiero teraz odpisuje
rozwiązałem to w sumie w prosty sposób, dodałem funkcję

  getPayerName(payIndex: number): string {
    return this.payers().at(payIndex).get('payerName').value;
  }

i wywołałem ją

<h2>{{getPayerName(payIndex)}}</h2>

dla potomnych chodzilo mi o mniej więcej o takie dodawanie formularza w formularzu ja na tej stronie:
https://www.tektutorialshub.com/angular/nested-formarray-example-add-form-fields-dynamically/

0

Hej,
mam jeszcze jeden problem a mianowicie w konsoli leci mi "ERROR Error: Cannot find control with path:" przy próbie wyswitlenia wartości za pomocą " <div formArrayName="bills" *ngFor="let bill of payerBills(payIndex)['controls']; let billsIndex = index">"

cały kod:

<form (keydown.enter)="$event.target.tagName == 'TEXTAREA'" [formGroup]="payersGroup" (ngSubmit)="onSubmit($event)"
      class="form-horizontal">
  <div class="panel panel-primary">
    <div class="panel-body">
      <div class="panel-heading">
        <h3 class="panel-title">Bills</h3>
      </div>

      <div>
        <div class="form-row">
          <div class="col-md-4">
            <label for="payerNameInput">Person name:</label>
            <input id="payerNameInput" type="text" class="form-control" #name
                   (keyup.enter)="addPayersButtonClick(name.value)"
                   [(ngModel)]="payerNameInput" [ngModelOptions]="{standalone: true}">
          </div>
          <div class="col">
            <button class="btn btn-primary" type="button" (click)="addPayersButtonClick(name.value)">Add person</button>
          </div>
        </div>
      </div>
      <br><br>

      <!-- Payers form group -->
      <div formArrayName="payers" *ngFor="let payer of payers()['controls']; let payIndex = index">
        <div class="well">
          <div [formGroupName]="payIndex">
            <div>
              <h2>{{getPayerName(payIndex)}}</h2>
            </div>

            <!--Display add bills form-->
            <div class="form-group form-row">
              <div class="col-md-2">
                <label [attr.for]="'bills'+payIndex">Bill:</label>
                <input [id]="'bills'+payIndex" type="text" class="form-control" formArrayName="bills" #bill>
              </div>
              <div class="col">
                <button class="btn btn-primary" type="button" (click)="addBillButtonClick(payIndex, bill.value)">Add
                  bill
                </button>
              </div>
              <div>
                <button (click)="removePayer(payIndex)">Remove</button>
              </div>
            </div>
          </div>


            <div formArrayName="bills" *ngFor="let bill of payerBills(payIndex)['controls']; let billsIndex = index">
              <table class="table" id="table">
              <thead>
              <tr>
                <th>Value</th>
                <th>Action</th>
              </tr>
              </thead>
              <tbody>
              <tr>
                <td>dupa</td>
                <td>
                  <button (click)="removePayerBill(payIndex,billsIndex)">Remove</button>
                </td>
              </tr>
              </tbody>
              </table>
            </div>

        </div>
      </div>
    </div>
    <br><br>
    <div class="panel-footer">
      <button class="btn btn-primary" type="submit">Calculate</button>
    </div>
  </div>
</form>

<table border="1">
  <tr>
    <th style="padding: 10px">FormGroup</th>
    <th style="padding: 10px">FormControl</th>
  </tr>

  <tr>
    <td style="padding: 10px">
      touched : {{payersGroup.touched}}
      <br/>dirty : {{payersGroup.dirty}}
      <br/>valid : {{payersGroup.valid}}
      <br/>value : {{payersGroup.value | json}}
    </td>

    <td style="padding: 10px">
      touched : {{payersGroup.get('payers').touched}}
      <br/>dirty : {{payersGroup.get('payers').dirty}}
      <br/>valid : {{payersGroup.get('payers').valid}}
      <br/>value : {{payersGroup.get('payers').value | json}}
    </td>
  </tr>
</table>

import {Component, OnInit} from '@angular/core';
import {FormGroup, FormBuilder, FormArray} from '@angular/forms';

@Component({
  selector: 'app-bills',
  templateUrl: './bills.component.html',
  styleUrls: ['./bills.component.css']
})

export class BillsComponent implements OnInit {
  payersGroup: FormGroup;
  payerNameInput = ' ';

  constructor(private fb: FormBuilder) {
  }

  ngOnInit(): void {
    this.payersGroup = this.fb.group({
      payers: this.fb.array([])
    });
  }

  /*
  *  payers functions
  * */
  payers(): FormArray {
    return this.payersGroup.get('payers') as FormArray;
  }

  removePayer(payIndex: number): void {
    this.payers().removeAt(payIndex);
  }

  createPayerFormGroup(name: string): FormGroup {
    return this.fb.group({
      payerName: name,
      bills: this.fb.array([])
    });
  }

  getPayerName(payIndex: number): string {
    return this.payers().at(payIndex).get('payerName').value;
  }

  /*
  *
  *  bills functions
  * */
  payerBills(payIndex: number): FormArray {
    return this.payers().at(payIndex).get('bills') as FormArray;
  }

  removePayerBill(payIndex: number, billIndex: number): void {
    this.payerBills(payIndex).removeAt(billIndex);
  }

  createPayerBillsGroup(bill: string): FormGroup {
    return this.fb.group({
      value: bill
    });
  }

  /*
  *
  *  buttons action
  * */
  addPayersButtonClick(name: string): void {
    this.payers().push(this.createPayerFormGroup(name));
    this.payerNameInput = '';
  }

  addBillButtonClick(payIndex: number, bill: string): void {
    this.payerBills(payIndex).push(this.createPayerBillsGroup(bill));
  }

  onSubmit($event: any): void {
    console.log(this.payersGroup.value);
  }

}

cały błąd
ERROR Error: Cannot find control with path: 'payers -> bills'
at _throwError (forms.js:2384)
at setUpFormContainer (forms.js:2366)
at FormGroupDirective.addFormArray (forms.js:5514)
at FormArrayName.ngOnInit (forms.js:5795)
at callHook (core.js:3038)
at callHooks (core.js:3008)
at executeInitAndCheckHooks (core.js:2960)
at refreshView (core.js:7187)
at refreshEmbeddedViews (core.js:8281)
at refreshView (core.js:7196)

0

Hej poradziłem sobie z tym ale teraz to już utknąłem chyba na dobre. Jak do tego stwoorzyć validacje ??

0

Walidatory dodajesz podając kolejny argument podczas tworzenia FormGroup/FormControl/FormArray.
https://angular.io/guide/form-validation
https://angular.io/guide/reactive-forms

0

Hej , dokumentacja to było pierwsze miejsce gdzie sprawdzałem ale dalej nie wiem jak to rozwiązać.
Chodzi np. o to :

      <div>
        <div class="form-row">
          <div class="col-md-4">
            <label for="payerNameInput">Person name:</label>
            <input id="payerNameInput" type="text" class="form-control" #name
                   (keyup.enter)="addPayersButtonClick(name.value)"
                   [(ngModel)]="payerNameInput" [ngModelOptions]="{standalone: true}">
          </div>
          <div class="col">
            <button class="btn btn-primary" type="button" (click)="addPayersButtonClick(name.value)">Add person</button>
          </div>
        </div>
      </div>

po wciśnięciu tego przycisku

<button class="btn btn-primary" type="button" (click)="addPayersButtonClick(name.value)">Add person</button>

chcę żeby było sprawdzone pole input: czyli czy jest uzupełnione i czy ilość znaków się zgadza itp.

            <input id="payerNameInput" type="text" class="form-control" #name
                   (keyup.enter)="addPayersButtonClick(name.value)"
                   [(ngModel)]="payerNameInput" [ngModelOptions]="{standalone: true}">

Nie jest to przycisk submit !! . Wymieniony button dodaje kolejną grupę z kolejnym polem do uzupełnienia które tez ma button i też w ten sam sposób ma być sprawdzone.

Na samym końcu ma być submit, który wysyła wszystko na backend jeżeli są dodane minimum 2 grupy.
No i nie wiem jak coś takiego zrobić i żeby się wyświetlały komunikaty.

0

Dodaj sobie walidator do tej grupy którą zwraca Ci metoda createPayerFormGroup(name) który by Ci sprawdził czy wszystkie pola są wypełnione lub dodaj sobie do każdego pola osobny walidator - z predefiniowanych masz Validators.required. Wtedy nad polem / obok pola / gdziekolwiek w wierszu, dodaj sobie sprawdzanie ngIfem czy FormGroup/FormControl.hasError() && FormGroup/FormControl.touched (możesz poczytać jeszcze o property pristine i dołożyć kolejny warunek) jeżeli tak - wyświetl jakąś informację odnośnie błędu. Na klika bym podpiął dwie rzeczy:

  1. oznaczenie wszystkich FormGroup/FormControl w payersGroup.controls.payers.controls jako touched
  2. sprawdzanie czy payersGroup.controls.payers.invalid jeśli nie, to dodałbym wiersz, jeżeli tak - nie robiłbym nic.

https://stackoverflow.com/questions/44998156/how-to-get-form-control-validation-errors-in-template-in-angular

1 użytkowników online, w tym zalogowanych: 0, gości: 1