skip to Main Content

I have a form where I am asking the user to fill out information about a grocery item threy want to add to their cart. Then they hit the add button item.

From my app.component.html

<form (ngSubmit)="addItem()">
  <label for="newItemName">Item Name:</label>
  <input type="text" [(ngModel)]="newItemName" id="newItemName" required>

  <label for="newItemPrice">Price:</label>
  <input type="number" [(ngModel)]="newItemPrice" id="newItemPrice" required>

  <label for="newItemQuantity">Quantity:</label>
  <input type="number" [(ngModel)]="newItemQuantity" id="newItemQuantity" required>

  <button type="submit">Add Item</button>
</form>

I also have it so they can remove items from the shopping cart.

From my app.component.html

<tbody>
    <tr *ngFor="let item of cartItems">
      <td>{{item.name}}</td>
      <td>{{item.price | currency}}</td>
      <td>
        <input type="number" [(ngModel)]="item.quantity" (change)="updateQuantity(item)" min="1">
      </td>
      <td>{{item.total | currency}}</td>
      <td>
        <button (click)="removeItem(item)">Remove</button>
      </td>
    </tr>
  </tbody>

When hitting submit, nothing happens and no errors show up in the console.

My app.component.ts:

import { Component } from '@angular/core';

interface CartItem {
  name: string;
  price: number;
  quantity: number;
  total: number;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  cartItems: CartItem[] = [];
  newItemName: string = '';
  newItemPrice: number = 0;
  newItemQuantity: number = 0;

  addItem() {
    if (this.newItemName && this.newItemPrice && this.newItemQuantity) {
      const newItem: CartItem = {
        name: this.newItemName,
        price: this.newItemPrice,
        quantity: this.newItemQuantity,
        total: this.newItemPrice * this.newItemQuantity
      };
      this.cartItems.push(newItem);
      this.newItemName = '';
      this.newItemPrice = 0;
      this.newItemQuantity = 0;
    }
  }

  updateQuantity(item: CartItem) {
    item.total = item.price * item.quantity;
  }

  removeItem(item: CartItem) {
    const index = this.cartItems.indexOf(item);
    if (index !== -1) {
      this.cartItems.splice(index, 1);
    }
  }

  calculateGrandTotal() {
    let grandTotal = 0;
    for (const item of this.cartItems) {
      grandTotal += item.total;
    }
    return grandTotal;
  }
}

My app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; // Import FormsModule for form handling

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule, // Add FormsModule for form handling
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

The items added to the cart should show up.
Now, just the template is showing, not the value of the items added.

2

Answers


  1. I have the feeling that the push array function, doesn’t trigger any changes into your template HTML, it doesn’t react…

    I suggest you do the following:

    addItem() {
        if (this.newItemName && this.newItemPrice && this.newItemQuantity) {
          // spread operator with arrays, you are creating a new object here
          const copyCart = [...this.cartItems];
    
          const newItem: CartItem = {
            name: this.newItemName,
            price: this.newItemPrice,
            quantity: this.newItemQuantity,
            total: this.newItemPrice * this.newItemQuantity
          };
    
          copyCart.push(newItem);
          // Angular should detect cartItems was changed;
          this.cartItems = [...copyCart];
          
          // this is just a suggestion, the addItem function
          // doesn't actually just add an item, it also resets the form
          // so a bit misleading function name, your function should do only one thing
          // you can then re-use this function somewhere else if need it
          this.resetForm();
        }
    }
    
    private resetForm(): void {
      this.newItemName = '';
      this.newItemPrice = 0;
      this.newItemQuantity = 0;
    }
    

    For removing an item, I think you will not have a problem since splice does affect the original array, in this case carItems

    Login or Signup to reply.
  2. On reproducing this with v15.1.2 I got the following error on component init:

    Error: NG01352: If ngModel is used within a form tag, either the name attribute must be set or the form
    control must be defined as ‘standalone’ in ngModelOptions.

    Example 1: <input [(ngModel)]="person.firstName" name="first">

    Example 2: <input [(ngModel)]="person.firstName" [ngModelOptions]="{standalone: true}">

    and the component properties were not bound to the form control. ie. they never changed from their default values – making the condition in addItem() always evaluate to false.

    Following the directions fixed the issue. ie. either add a name attribute or [ngModelOptions]="{standalone: true}" to each form control.

    Note that a value of 0 in either of the numeric inputs will cause the condition to evaluate to false, and therefore nothing will happen.

    Live example: https://stackblitz.com/edit/angular-cynoqr?file=src/main.html

    <input
        type="text"
        [(ngModel)]="newItemName"
        id="newItemName"
        name="newItemName"
        required
      />
    
      <label for="newItemPrice">Price:</label>
      <input
        type="number"
        [(ngModel)]="newItemPrice"
        id="newItemPrice"
        name="newItemPrice"
        required
      />
    
      <label for="newItemQuantity">Quantity:</label>
      <input
        type="number"
        [(ngModel)]="newItemQuantity"
        id="newItemQuantity"
        name="newItemQuantity"
        required
      />
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search