Search code examples
angularangular-reactive-formsangular-formsjavascript-framework

Why am I obtaining this error message retrieving objects from a JSON file after this FormArray changes in my reactive form?


I am working on an Angular project using reactive form and introducing FormArray (beacause I have a situation where a field is dinamically created as multiple fields) I am facing the following problem.

Basically into a form defined my HTML code I have something like this:

<div class="col-10">
    <ng-container *ngFor="let commessa of commessaList.controls; index as idx">
    <div class="row">
    <div class="col-sm-8">
      <input type="text" [ngClass]="{'error':commessa.invalid && commessa.touched}"
                 [formControlName]="idx"
                 class="form-control" id="commessa">
    </div>

    <div class="col-sm-2">
      <button type="button" *ngIf="idx===0" (click)="addCommessaField()" class="btn btn-success"
        [ngClass]="'pad'"><i class="fa fa-plus-circle" aria-hidden="true"></i></button>

      <button (click)="deleteCommessaField(idx)" *ngIf="idx!==0" class="btn btn-danger">
        <i class="fa fa-trash" aria-hidden="true"></i>
      </button>
    </div>
    </div>
    </ng-container>

    </div>
</div>

This section is used to define the hightlighted section of my form (where I can add multiple "Commessa" fields:

enter image description here

Then into my TypeScript code I have defined the orderForm: FormGroup; object that I use to define the form fields and the related validation rules, I set this into the ngOnInit() method:

ngOnInit() {

    this.orderFormValues = new OrderFormValues();

    console.log("orderFormValues VALUES: " + this.orderFormValues.statoOrdine);

    this.orderForm = this.fb.group({
    idOrdine: [null, [Validators.required]],
    dataInserimentoOrdine: [new Date(), [Validators.required]],
    statoOrdine: [null, [Validators.required, Validators.minLength(5)]],
    //commessa: [null, [Validators.required, Validators.minLength(5)]],
    commessaList: new FormArray([
    new FormControl('', [Validators.required, Validators.minLength(5)])
    ]),

    CIG: [null, [Validators.required, Validators.pattern("^[a-zA-Z0-9]{10}$")]],
    dataInizioAttivita: [null, [Validators.required]],
    dataFineAttivita: [null, [Validators.required]],
    referente: [null, [Validators.required]],
    ruoloReferente: [null, [Validators.required]],
    tipologiaDiPartecipazione: [null, [Validators.required, Validators.minLength(5)]],
    quotaPercentualeDiRTI: [null, [Validators.max(100)]],

    cliente: [null, [Validators.required]],
    vatCliente: [null, [Validators.required]],
    clienteFinale: [null, []],
    vatClienteFinale: [null, []],

    tipologiaContratto: [null, []],
    importoContratto: [null, [Validators.required]],
    linkContratto: [null, [Validators.required]],
    dataSottoscrizioneContratto: [null, [Validators.required]],

    nomeSocieta: [null, [Validators.required]],
    vatSocieta: [null, []],
    buName: [null, [Validators.required]],

    presenzaAQ: [false, [Validators.required]],
    linkIdentificativoAQ: [null, []],
    accordoQuadro: [null, []],
    residuoAccordoQuadro: [null, []],
    compagineDiAQ: [null, []]

    });



    this.ordersService.getAllOrders().then(orders => {
        this.orders = orders;
        console.log("RETRIEVED ORDERS: ", orders);
        this.loading = false;
    });

        .........................................................................................
        .........................................................................................
        .........................................................................................
}

As you can see into the FormGroup defintion the section related to the multiple "Commessa" field is defined as FormArray in this way:

commessaList: new FormArray([
    new FormControl('', [Validators.required, Validators.minLength(5)])
]),

For completeness I add that then in my TypeScript code I also have these two methods used to insert the value inserted by the user in the multiple Commessa fiels in this FormArray object:

addCommessaField() {
    this.commessaList.push(new FormControl('', [Validators.required, Validators.minLength(5)]));
}

deleteCommessaField(index: number) {
    if (this.commessaList.length !== 1) {
        this.commessaList.removeAt(index);
    }
    console.log(this.commessaList.length);
}

As you can see in the previous code snippet into my ngOnInit() method I am performing also this call to an OrderService object:

this.ordersService.getAllOrders().then(orders => {
    this.orders = orders;
    console.log("RETRIEVED ORDERS: ", orders);
    this.loading = false;
});

This call simply retrieves a list of orders (at the moment mocked into a JSON file) that are displayed in the homepage and here I am obtaining a strange error.

The code of my getAllOrders() service method is simply this one:

getAllOrders() {
    return this.http.get<any>('assets/json_mock/ordini.json')
    .toPromise()
    .then(res => <Order[]>res.data)
    .then(data => { return data; });
}

As you can see it retrives and return orders from this ordini.json file.

The problem is that calling the getAllOrders() service method it retrieve the orders list but in the Chrome console I am also obtaining this error message:

core.js:6228 ERROR Error: Cannot find control with name: '0'
    at _throwError (forms.js:3576)
    at setUpControl (forms.js:3398)
    at FormGroupDirective.addControl (forms.js:7679)
    at FormControlName._setUpControl (forms.js:8451)
    at FormControlName.ngOnChanges (forms.js:8368)
    at FormControlName.wrapOnChangesHook_inPreviousChangesStorage (core.js:26966)
    at callHook (core.js:4730)
    at callHooks (core.js:4690)
    at executeInitAndCheckHooks (core.js:4630)
    at selectIndexInternal (core.js:9748)

The strange thing is that it happens after that I implemented this multiple "Commessa" fields using the previous FormArray (before I had only a single "Commessa" input field and I had not this error). I suspect that maybe the error could be in my original JSON content but I am not understanding why and how I can solve this problem.

Following the content of my ordini.json file:

{
  "data": [
    {
      "id": 1,

      "referente": {
        "name": "Mario",
        "surname": "Rossi",
        "complete_name": "Mario Rossi",
        "role": "Operation Manager",
        "avatar": "mario-rossi.jpg"
      },

      "company": {
        "name": "TEST S.p.A.",
        "VAT": "IT 03318271214",

        "BU": {
          "name": "Digital Solution",
          "code": "DS"
        }
      },

      "dettaglio_ordine": {
        "data_inserimento": "08/08/2020",


        "commessa": {
          "code": "AAA0001"
        },

        "identificativo_contratto_hyperlink": "LINK-ID-CONTRATTO-TEST",
        "tipologia_contratto": "ORDINE",
        "presenza_AQ": true,
        "identificativo_AQ_hyperlink": "LINK-AQ-TEST",
        "accordo_quadro": 12,
        "importo_contratto": 122000,
        "residuo_AQ": 20000,
        "compagine_di_AQ": "COMPAGINE-DI-AQ-TEST",
        "quota_percentuale_di_RTI": 20,
        "tipologia_di_partecipazione": "GARA PUBBLICA",
        "cig": "CIG-TEST-1",
        "cliente": "CLIENTE-TEST-1",
        "vat_cliente": "VAT-CLIENTE",
        "cliente_finale": "CLIENTE-FINALE-TEST-1",
        "vat_cliente_finale": "VAT-CLIENTE-FINALE",
        "data_sottoscrizione_contratto": "8/12/2020",
        "data_inizio_attivita": "8/28/2020",
        "data_fine_attivita": "8/31/2020",
        "stato_ordine": "CHIUSO"
      }
    },

    {
      "id": 2,

      "referente": {
        "name": "Mario",
        "surname": "Rossi",
        "complete_name": "Mario Rossi",
        "role": "Operation Manager",
        "avatar": "mario-rossi.jpg"
      },

      "company": {
        "name": "Blabla S.p.A.",
        "VAT": "IT 03318271214",

        "BU": {
          "name": "Cyber Security",
          "code": "CS"
        }
      },

      "dettaglio_ordine": {
        "data_inserimento": "09/08/2020",


        "commessa": {
          "code": "AAA0002"
        },

        "identificativo_contratto_hyperlink": "LINK-ID-CONTRATTO-TEST",
        "tipologia_contratto": "ORDINE",
        "presenza_AQ": false,
        "identificativo_AQ_hyperlink": "LINK-AQ-TEST",
        "accordo_quadro": 12,
        "importo_contratto": 122000,
        "residuo_AQ": 20000,
        "compagine_di_AQ": "COMPAGINE-DI-AQ-TEST",
        "quota_percentuale_di_RTI": 20,
        "tipologia_di_partecipazione": "GARA PUBBLICA",
        "cig": "CIG-TEST-2",
        "cliente": "CLIENTE-TEST-1",
        "vat_cliente": "VAT CLIENTE TEST",
        "cliente_finale": "CLIENTE-FINALE-TEST-2",
        "vat_cliente_finale": "VAT-CLIENTE-FINALE-TEST",
        "data_sottoscrizione_contratto": "8/12/2020",
        "data_inizio_attivita": "8/28/2020",
        "data_fine_attivita": "8/31/2020",
        "stato_ordine": "CHIUSO"
      }
    },

    {
      "id": 3,

      "referente": {
        "name": "Francesco Nicola",
        "surname": "Romano",
        "complete_name": "Francesco Verdi",
        "role": "Operation Manager",
        "avatar": "francesco-romano.jpg"
      },

      "company": {
        "name": "Blabla S.p.A.",
        "VAT": "IT 03318271214",

        "BU": {
          "name": "Cyber Security",
          "code": "CS"
        }
      },

      "dettaglio_ordine": {
        "data_inserimento": "10/08/2020",


        "commessa": {
          "code": "AAA0002"
        },

        "identificativo_contratto_hyperlink": "LINK-ID-CONTRATTO-TEST",
        "tipologia_contratto": "ORDINE",
        "presenza_AQ": false,
        "identificativo_AQ_hyperlink": "LINK-AQ-TEST",
        "accordo_quadro": 12,
        "importo_contratto": 122000,
        "residuo_AQ": 20000,
        "compagine_di_AQ": "COMPAGINE-DI-AQ-TEST",
        "quota_percentuale_di_RTI": 20,
        "tipologia_di_partecipazione": "GARA PUBBLICA",
        "cig": "CIG-TEST-3",
        "cliente": "CLIENTE-TEST-3",
        "vat_cliente": "XXX123",
        "cliente_finale": "CLIENTE-FINALE-TEST-3",
        "vat_cliente_finale": "YYY321",
        "data_sottoscrizione_contratto": "8/12/2020",
        "data_inizio_attivita": "8/28/2020",
        "data_fine_attivita": "8/31/2020",
        "stato_ordine": "CHIUSO"
      }

    }
  ]
}

As you can see here in the objects defined in this JSON file the commessa field is defined in this way:

"commessa": {
    "code": "AAA0002"
},

maybe is wrong or maybe the problem is elsewhere.

What am I missing? Why am I obtaining this error? How can I try to fix this bug?


Solution

  • You are missing the formArrayName div in html.

    Make sure to enclose the HTML with the formArrayName="commessaList"

    <div formArrayName="commessaList">
      <div class="form-group row">
        <label for="commessa" class="col-sm-2 col-form-label">Commessa</label>
        <div class="col-sm-10">
          <ng-container *ngFor="let commessa of commessaList.controls; index as idx">
            ................
            ................
          </ng-container>
        </div>
      </div>
    </div>