Blah Foo
Blah Foo

Reputation: 21

Angular - edit textbox in grid to update row value

I'm trying to give user the ability to update the quantity of their selection before product checkout. The code below allows only 1 character in the textbox. What changes can I make to allow user enter up to 2 characters?

https://stackblitz.com/edit/angular-kfiqrb?file=src%2Fapp%2Ftable-basic-example.html This solution works but the column is a div not a textbox

export class ProductSelection {
  id!: number;
  name!: string;
  itemPrice!: number;
  quantity!: number;
  totalPrice!: number;
}

html file

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>ItemPrice</th>
      <th>Quantity</th>
      <th>Total</th>
    </tr>
  </thead>
  <tbody *ngFor="let p of products; let i = index">
    <tr>
      <td>{{ p.name }}</td>
      <td>{{ p.itemPrice }}</td>
      <td>
        <input type="text" value="{{ p.quantity }}" (input)="quantitychange($event, i)" />
      </td>
      <td>{{ p.totalPrice }}/td></td>
    </tr>
  </tbody>
</table>

<div>
 <input type="button" (click)="checkout()" value="submit" />
</div>

ts file

products: ProductSelection[] = [];

  constructor() {
    this.products= [
     { id = 1, name = "name1", itemPrice: 3, quantity: 3, totalPrice: 9 },
     { id = 1, name = "name2", itemPrice: 1, quantity: 10, totalPrice: 10 },
     { id = 1, name = "name3", itemPrice: 4, quantity: 4, totalPrice: 16 }
    ]
  }
  

  quantitychange(event: any, row: number) {
    let item = this.products[row];
    item.totalPrice = (item.itemPrice * Number(event.data));
    item.quantity = event.data;
    this.products[row] = item;
  }

  checkout() {
   let total = 0;
   this.products.foreach(i => total += i.totalPrice);
   //send to service
  }

I get event data as undefined when I use (focusout) event.

PS: Sorry, I can't access github from my machine else I'd have created the stackblitz for this one. Are there any other alternatives?

Upvotes: 0

Views: 101

Answers (2)

Bilal Hamza
Bilal Hamza

Reputation: 1

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>ItemPrice</th>
      <th>Quantity</th>
      <th>Total</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let p of products; let i = index">
      <td>{{ p.name }}</td>
      <td>{{ p.itemPrice }}</td>
      <td>
        <input type="number" [value]="p.quantity" (input)="quantitychange($event, i)" />
      </td>
      <td>{{ p.totalPrice }}</td>
    </tr>
  </tbody>
</table>

<div>
 <input type="button" (click)="checkout()" value="submit" />
</div>

Here, the changes i have made are:

  1. Moved *ngFor="let p of products; let i = index" from the <tbody> tag to the <tr> tag, because it is to be repeated for all new rows added in the table.

  2. [value]="p.quantity", this way ensures that when the value changes the quantity will be updated.

  3. Found a syntax error <td>{{ p.totalPrice }}/td></td> which is to be <td>{{ p.totalPrice }}</td>

Moreover, u can change the input type to number ensuring only numbers are entered.

<input type="number" [value]="p.quantity" (input)="quantitychange($event, i)" />

Upvotes: 0

Naren Murali
Naren Murali

Reputation: 56052

You can just use Template Driven Forms for this, [(ngModel)] will two way bind the values to the data object so that when you update in code it will reflect in UI and when you type in HTML it will update the data. You can use (ngModelChange) to trigger the calculation whenever the input changes, I also changed the input to accept only number values!

Template Driven Forms Docs

import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
export class ProductSelection {
  id!: number;
  name!: string;
  itemPrice!: number;
  quantity!: number;
  totalPrice!: number;
}
@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, FormsModule],
  template: `
   <table>
  <thead>
    <tr>
      <th>Name</th>
      <th>ItemPrice</th>
      <th>Quantity</th>
      <th>Total</th>
    </tr>
  </thead>
  <tbody *ngFor="let p of products; let i = index">
    <tr>
      <td>{{ p.name }}</td>
      <td>{{ p.itemPrice }}</td>
      <td>
        <input type="number" [(ngModel)]="p.quantity" (ngModelChange)="quantitychange($event, i)" />
      </td>
      <td>{{ p.totalPrice }}</td>
    </tr>
  </tbody>
</table>

<div>
 <input type="button" (click)="checkout()" value="submit" />
</div>
  `,
})
export class App {
  products: ProductSelection[] = [];

  constructor() {
    this.products = [
      { id: 1, name: 'name1', itemPrice: 3, quantity: 3, totalPrice: 9 },
      { id: 1, name: 'name2', itemPrice: 1, quantity: 10, totalPrice: 10 },
      { id: 1, name: 'name3', itemPrice: 4, quantity: 4, totalPrice: 16 },
    ];
  }

  quantitychange(event: any, row: number) {
    let item = this.products[row];
    item.totalPrice = item.itemPrice * Number(event);
    item.quantity = event.data;
    this.products[row] = item;
  }

  checkout() {
    let total = 0;
    this.products.forEach((i) => (total += i.totalPrice));
    alert(`Total Checkout quantity: ${total}`);
    //send to service
  }
}

bootstrapApplication(App);

Stackblitz Demo

Upvotes: 0

Related Questions