Angular Reactive Form - ng-select in form array easily implemented offline but encounters issues when connected to the internet

My goal is to choose a product with a price, specify the quantity, and then select another product from the list. The issue arises when I deploy the code online because it duplicates the first selected product every time the addItem() function is triggered.

I am struggling to identify the cause of this problem.

This is the relevant component code:

pform: FormGroup;
iform:FormGroup;

createDataForm() {
  this.pform = this.fb.group({
    amount: [''],
    issueDate: ['', Validators.required],
    profileId: ['', Validators.required],
    items: this.fb.array([
      this.iform = this.fb.group({
        product: [{ value: {}, disabled:false}],
        quantity: [0, Validators.min(1)],
        price: [''],
        total: ['']
      })
    ])
  })
}

get items() {
  return this.pform.get('items') as FormArray;
}

addItem() {
  this.items.push(this.fb.group({
    product: [{ value: {}, disabled:false}],
    quantity: [0, Validators.min(1)],
    price: [''],
    total:['']
  }));
  this.calculateTotal();
}

removeItem(index: number): void {
  this.items.removeAt(index)
  this.calculateTotal()
}

calculateTotal() {
  let sum = 0;
  this.items.controls.forEach(control => {
    sum += control.value.total;
  });
  this.pform.patchValue({ amount:sum });
  console.log(sum)
}

// Function to calculate each product's total
calItemTotal(control: FormGroup) {
  const quantity = control.value.quantity;
  const price = control.value.price;
  control.patchValue({ total: quantity * price });
  // this.calculateTotal();
}

compareFn(product: Product, _product: Product) {
  return product && _product ? product.id === _product.id : product === _product;
}

// Assign price for each product selection
onSelectProduct(event: any, index: number) {
  const selectedProduct = event;
  this.items.at(index).get('price').setValue(selectedProduct.price);
}

This section displays the corresponding HTML code:

<div formArrayName="items">
  <div *ngFor="let item of items.controls; let i = index">
    <hr/>
    <h5>Product {{i + 1}}</h5>
    <div  [formGroup]="iform">
      <div class="row">

        <!-- Product -->
        <div class="col-md-4">
          <div class="form-group row">
            <label class="col-sm-3 col-form-label" for="product">Product</label>
            <div class="col-sm-9">
              <ng-select
              formControlName="product"
              [compareWith]="compareFn"
              [formControl]="item?.get('product')"
              [items]="products"
              (change)="onSelectProduct($event, i)"
              bindLabel="product"
              bindValue="product">
              </ng-select>
            </div>
          </div>
        </div>

          <!-- Price -->
          <div class="col-md-1">
            <div class="form-group row">
              <!-- <label class="col-xs-3 col-form-label" for="price">P</label> -->
              <div class="col-xs-6 offset-1">
                <input type="number" class="form-control"
                id="price" placeholder="0"
                formControlName="price" [formControl]="item?.get('price')" readonly>
              </div>
            </div>
          </div>

        <!-- Qty -->
        <div class="col-md-3">
          <div class="form-group row">
            <label class="col-xs-2 offset-1 col-form-label" for="quantity">Qty</label>
            <div class="col-xs-6 offset-1">
              <input type="number" class="form-control"
              id="quantity" placeholder="0"
              formControlName="quantity" [formControl]="item?.get('quantity')" (change)="calItemTotal(item)">
            </div>
          </div>
        </div>

        <!-- Total -->
        <div class="col-md-3">
          <div class="form-group row">
            <label class="col-xs-3 col-form-label" for="total">Amt</label>
            <div class="col-xs-6 offset-1">
              <input type="number" class="form-control"
              id="total" placeholder="0"
              formControlName="total" [formControl]="item?.get('total')" readonly>
            </div>
          </div>
        </div>

        <!-- Button -->
        <div class="col-md-1">
          <div class="form-group row">
            <span (click)="removeItem(i)" class="btn btn-sm btn-warning btn-rounded btn-fw"><span><i class="icofont icofont-trash"></i></span></span>
          </div>
        </div>

      </div>
    </div>

  </div>
</div>

Answer №1

  1. It is recommended to have each item in the FormArray contain its own unique FormGroup instance using [formGroupName]="i" rather than sharing the same FormGroup instance for all items.

  2. Avoid redundant use of both [formControlName] and [formControl]. Choose one method and ensure correct typing, especially when enabling strict type-checking mode in tsconfig.json.

  3. To streamline item creation, implement a function (createItemFormGroup) that generates the item's FormGroup instance efficiently without repetition.

<div [formGroup]="pform">
  <div formArrayName="items">
    ...
  </div>
</div>
createDataForm() {
  this.pform = this.fb.group({
    amount: [''],
    issueDate: ['', Validators.required],
    profileId: ['', Validators.required],
    items: this.fb.array([
      this.createItemFormGroup()
    ]),
  });
}

createItemFormGroup() {
  return this.fb.group({
    product: [{ value: {}, disabled: false }],
    quantity: [0, Validators.min(1)],
    price: [''],
    total: [''],
  })
}

addItem() {
  this.items.push(
    this.createItemFormGroup()
  );
  this.calculateTotal();
}

Check out the demo on StackBlitz

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Remove a row from an ng-bootstrap table

I've managed to successfully implement the ng-bootstrap table full example. Deleting objects from the DOM and database works fine, but I'm struggling to figure out how to delete a row from the view without having to reload the page. It's i ...

What is the best approach to utilizing directives across multiple modules within Angular?

Recently, I created a directive called uppercase-input.directive.ts I attempted to import and use this directive in multiple components, but encountered the following error I have only shared one file here (organization.module.ts), but there are several ot ...

Loading AngularJS multiple times

I'm facing a challenge while upgrading my angularJs Application to Webpack4. This is how I've set it up: vendor.ts import "angular"; import "angular-i18n/de-de"; import "angular-route"; and main.ts import {MyAppModule} from "./my-app.app"; ...

Tips for styling dates in an Angular Material table

My web API provides me with this data: https://i.sstatic.net/9pGuO.png The data is in the form of an array of IOferta export interface IOferta { id: string idPresentada: string; descripcion: string; fechaPresentacion: Date; responsable: string; pre ...

Utilizing Angular Material's <mat-selection-list> and <mat-list-option> components seamlessly between different sections of a template

How can a <mat-list-option> declared in component sub subscribe to a <mat-selection-list> outside of component sub (for example, in component app)? (Unfortunately, I couldn't get Stackblitz to work due to my corporate's proxy restric ...

Leveraging a virtual directory to co-host a single-page application and backend API within a shared Azure Web

I'm attempting to host both my Angular SPA and run the Spring-boot backend API on the same Azure Web app in order for them to share the same domain. To achieve this, I have set up a virtual directory api/ for running the backend and directed the root ...

Retrieve individual data record from AngularFireDatabase

Welcome to my blog showcasing various screenshots: https://i.sstatic.net/cAtci.png My current focus is on retrieving a single course using its id, and I have the following code snippet for that purpose: Service: getSingle(uid: string) { return thi ...

Guide on extracting query parameters from a URL with the activated router in Angular

Is there a way to access the current URL along with its query parameters using an activated router in Angular? constructor(private router: Router, private route: ActivatedRoute) { } ngOnInit() { this.router.events.pipe( fi ...

angular click triggers the following content

How can I make the following content appear when clicked? I have a list of content that displays up to 20 items, but I want to show the rest when clicked. I have created the nextMovieList method for this purpose. import { Component, OnInit } from ' ...

Determining the accurate object from a nested type in Typescript is essential

I'm currently facing a challenge with Typescript in inferring the correct object within a switch case. I find it puzzling why my scenario works as expected with a union type but not with an object. Here is the code from the playground link: interface ...

Is it possible to use optional destructured arguments in a Typescript function?

Is there a way to create a function that accepts an optional object argument using destructuring in Typescript? myFunction({opt1, opt2}?: {opt1?: boolean, opt2?: boolean}) The error message "A binding pattern parameter cannot be optional in an implementa ...

A step-by-step guide on generating a TypeScript class using JSON data

Working with Angular and making a call to an external API. The JSON data is structured as follows: [ { "AccessGroupsIdList": [], "FirstName": "Greg", "LastName": "Tipton", ...

The drop down list does not support the 'click' function and is throwing a TypeError

Could someone please assist in troubleshooting my code? I am trying to select a specific value from a dropdown list but is encountering difficulties. The code is able to retrieve the values from the dropdown but is unable to successfully click on the mat ...

Unable to determine all parameters for Angular's DataService

I have been working on developing a versatile service and came across an informative article: https://medium.com/@krishna.acondy/a-generic-http-service-approach-for-angular-applications-a7bd8ff6a068 that guided me in creating my DataService. Here is a snip ...

Verify whether the setter function has been utilized

Within my service, I have implemented a setter and getter method: export class fooService { set foo(value: number): void { this._privateFoo = value; } get foo(): number { return this._privateFoo; } I recently created a mock of the service ...

Subclass callback with parameters

Having some trouble with one of my TypeScript functions and I'm hoping it's not a silly question. I believe what I'm attempting should work in theory. Here's a simplified version of my issue to demonstrate where the problem lies (the o ...

Creating an application using AngularJS 4 and the Express generator

Recently, I successfully created a basic angular 4 application using this helpful tutorial: https://scotch.io/tutorials/mean-app-with-angular-2-and-the-angular-cli My next challenge is integrating the angular 4 app with an express application generated b ...

Issue with importing aliases in Angular 7 production environment

Hello everyone! I have encountered an issue where using alias on import and building the project in production mode (--prod flag) results in the alias being undefined. Interestingly, this behavior does not occur in development mode. Any suggestions on how ...

Tips for displaying HTML content from a JSON web template

Currently, I am working with a JSON web template that consists of nested elements. My goal is to render HTML based on the content of this JSON web template. I attempted using ngx-schema-form, however my JSON does not contain properties variables. I also t ...

Storing data in Angular 2 services for safekeeping

I have multiple sub-components that each receive specific data from a main component. These sub-components only receive the data necessary for display purposes. My goal now is to create a service that can make a request to a server. The problem is, this re ...