The saved editable input number is automatically pushed even without needing to click on save or cancel

I am working with a datatable, chart, and a label that shows the latest added value.

  • The table and chart display time-series data for the last 30 minutes, including the timestamp and a random numerical value between 0 and 999.
  • Every 10 seconds, a new data object is added to the array while the oldest one is removed, ensuring that only the last 30 minutes of data are visible. The Latest Value label reflects the most recent addition.

My problem arises when attempting to edit rows in the table. After editing a cell by inputting numbers, if I cancel the edit without saving (by clicking X), the values in the table and chart update after 10 seconds. This behavior is unexpected as the edit was canceled. Similarly, just typing in the input field without saving or canceling the edit also triggers changes in the displayed values.

I suspect this issue has to do with two-way binding in the table, but I am unsure how to resolve it.

I tried the following solution, but encountered the same results:

clonedData = [];

ngOnChanges() {
this.clonedData = [...tableData]}

In the HTML table, instead of using tableData for the value, I attempted using clonedData as shown in the code snippet above.

Here is a link to the StackBlitz project: https://stackblitz.com/edit/angular-43vasb?file=src%2Fapp%2Fmain%2Ftable%2Ftable.component.ts,src%2Fapp%2Fmain%2Fmain.component.ts,src%2Fapp%2Finterface.ts,src%2Fapp%2Fdata.service.ts,src%2Fapp%2Fmain%2Ftable%2Ftable.component.html

Table TypeScript code:

export class TableComponent {
  @Input() tableData: IData[] = [];

  editedData: { [s: string]: IData } = {};

  constructor(private dataService: DataService) {}

  onRowEditInit(data: IData) {
    this.editedData[data.id] = { ...data };
    console.log(this.editedData[data.id]);
  }

  editRow(data: IData, row: any) {
    this.tableData[row] = data;
    this.dataService.setData(this.tableData);
    delete this.editedData[data.id];
  }

  onRowEditCancel(data: IData, row: number) {
    this.tableData[row] = this.editedData[data.id];
    delete this.editedData[data.id];
  }
}

Table HTML code:

<div class="container">
  <p-table
    [value]="tableData"
    dataKey="id"
    editMode="row"
    scrollHeight="flex"
    styleClass="p-datatable-gridlines"
    [rows]="8"
    [scrollable]="true"
  >
    <ng-template pTemplate="header">
      <tr>
        <th class="time">Time</th>
        <th class="value">Value</th>
        <th class="action"></th>
      </tr>
    </ng-template>
    <ng-template
      pTemplate="body"
      let-data
      let-editing="editing"
      let-ri="rowIndex"
    >
      <tr [pEditableRow]="data">
        <td class="p-column-title">
          <p-cellEditor>
            <ng-template pTemplate="input">
              <input pInputText type="text" [(ngModel)]="data.time" />
            </ng-template>
            <ng-template pTemplate="output">
              {{ data.time | date : "yyyy-MM-dd HH:mm:ss" }}
            </ng-template>
          </p-cellEditor>
        </td>
        <td>
          <p-cellEditor>
            <ng-template pTemplate="input">
              <input pInputText type="number" [(ngModel)]="data.value" />
            </ng-template>
            <ng-template pTemplate="output">
              {{ data.value | number : "1.2-2" }}
            </ng-template>
          </p-cellEditor>
        </td>
        <td class="action-button">
          <div class="flex align-items-center justify-content-center gap-2">
            <button
              *ngIf="!editing"
              pButton
              pRipple
              type="button"
              (click)="onRowEditInit(data)"
              pInitEditableRow
              icon="pi pi-pencil"
              class="p-button-rounded p-button-text"
            ></button>
            <button
              *ngIf="editing"
              pButton
              pRipple
              (click)="editRow(data, ri)"
              type="button"
              pSaveEditableRow
              icon="pi pi-check"
              class="p-button-rounded p-button-text p-button-success mr-2"
            ></button>
            <button
              *ngIf="editing"
              pButton
              pRipple
              (click)="onRowEditCancel(data, ri)"
              type="button"
              pCancelEditableRow
              icon="pi pi-times"
              class="p-button-rounded p-button-text p-button-danger"
            ></button>
          </div>
        </td>
      </tr>
    </ng-template>
  </p-table>
</div>

Answer №1

[Please take note that most examples for PrimeNG do not include live charts, which may not address your specific use-case. This could explain why you are encountering issues if you are following those tutorials.]

The main issue lies in the binding: by directly binding the time and value to the actual table data, any edits made - whether accepted or cancelled - will affect the original table data. To resolve this, it is advisable to bind to separate variables. I have made modifications to your stackblitz code as follows:

  1. I have created three new variables idBeingEdited, timeBeingEdited, and valueBeingEdited in [table.comp.ts] and bound them in the template [table.comp.html] instead of using data.time and data.value. This approach ensures that the 'original' data remains unchanged (particularly crucial for row order) while working solely with these local/bound values.
  2. Your onRowEditInit() method has been updated to set the values of these variables to match the data being edited.
  3. The onRowEditCancel() method has been removed entirely since we now manipulate non-original data, and no alterations (in logic or data) are needed if you simply cancel the operation.
  4. The editRow() method has been modified to update only the original data at the specified id without making any other changes.

Changes in table.com.ts:

idBeingEdited: number = null;
timeBeingEdited: number = null;
valueBeingEdited: number = null;

(...)

onRowEditInit(data: IData) {
    this.idBeingEdited = data.id;
    this.timeBeingEdited = data.time;
    this.valueBeingEdited = data.value;
}

editRow() {
    this.tableData.forEach((row, i) => {
      if (row.id == this.idBeingEdited) {
        this.tableData[i].time = this.timeBeingEdited;
        this.tableData[i].value = this.valueBeingEdited;
      }
    });
    this.dataService.setData(this.tableData);
}

In table.comp.html:

  • The input on line 28 (
    <input pInputText type="text" [(ngModel)]="data.time" />
    ) should be changed to
    <input pInputText type="text" [(ngModel)]="timeBeingEdited" />
  • The input on line 38 (
    <input pInputText type="number" [(ngModel)]="data.value" />
    ) should be changed to
    <input pInputText type="number" [(ngModel)]="valueBeingEdited" />
  • The click event on line 61 (
    (click)="editRow(data, ri)"
    ) should be changed to (click)="editRow()"

You can view a demo of these changes 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

Reactjs-ffsevents does not exist as a function

An error occurred: TypeError: fsevents is not a function. This issue is located in the FSEventsWatcher file at line 162. A new FSEventsWatcher was attempted to be created in jest-haste-map, triggering this error. The watcher creation process involved map ...

Step-by-step guide on installing both Angular and Nodejs within a single folder

I'm diving into the world of NodeJs and Angular, and I recently created a simple NodeJS application following instructions from this link. However, I encountered an issue when trying to install Angular alongside NodeJS. After running ng new angular-cr ...

Transforming a non-specific type into a container permits precarious assignments

I'm encountering an issue with the code snippet provided below. Despite having a specific type where Type<boolean> cannot be assigned to Type<true>, when wrapping it in an object type (BoxType as shown), suddenly BoxType<boolean> wro ...

Retrieve properly formatted text from the editor.document using the VSCode API

I have been working on creating a personalized VSCode extension that can export the current selected file contents as a PDF. Although PrintCode exists, it does not fit my specific needs. The snippet of code I am currently using is: const editor = vscode.w ...

Encountering difficulty with retrieving information from a shared service on Angular 6

Attempting to pass JSON data from one component to another component (like parent to child) using a service. The service has two methods: setJsonData and getJsonData. Service Class import { Injectable } from '@angular/core'; @Injectable({ pr ...

Tips for obtaining files and videos from Google Drive utilizing Angular 6/7

Trying to integrate Google Drive with my Angular 7 application for the first time. I am looking to download a video file from Google Drive and play it in my Angular Application. After extensive research, I haven't found a solution yet. Can someone pro ...

Rotating carousel powered by object data

Here is a carousel that I have set up to display images from an object called pictures: <div class="carousel-inner mb-5"> <div *ngFor="let pic of pictures; let i = index"> < ...

Can I modify the cookie domain for NestJS SessionModule on a per-request basis?

I am currently using NestJS with SessionModule to handle user cookies successfully. However, I have a requirement to override the domain name for certain requests. I am uncertain about how to achieve this within NestJS, as the domain setting appears to b ...

Instead of returning an Observable<HttpResponse> for HttpClient.post, consider returning an Observable<boolean> instead

Is there a way for me to have my method return an Observable<boolean> instead of the Observable<HttpClient<AuthResponse>>? This is the current code I'm working with: login(username: string, password: string): Observable<boolea ...

Can the inclusion of additional parameters compromise the type safety in TypeScript?

For demonstration purposes, let's consider this example: (playground) type F0 = (x?: string) => void type F1 = () => void type F2 = (x: number) => void const f0: F0 = (x) => console.log(x, typeof(x)) const f1: F1 = f0 const f2: F2 = f1 f ...

Can an Angular Component be displayed using a Serverless function like Lambda on AWS?

I have a single-page application developed in JavaScript using the Angular 6 Framework, and I am interested in dynamically rendering an Angular Component that is hosted on a remote server. Currently, I am utilizing viewContainerRef to dynamically render ...

Redirect to the homepage if the requested page is not found in IIS

Within my IIS Website, there are three applications being hosted. The main website is an Angular App, alongside an API application housing all APIs and another application that is a pure javascript project hosted under the application alias /vmenu/. Any r ...

Prevent entry into property in Ionic 2 course

I receive a dynamic translation file from a server periodically, and I'm unable to modify its format. When a new page is instantiated in my Ionic App, I assign the value from storage to this.translations. See the constructor below: constructor(stora ...

Change typescript so that it shows "require" instead of "import" when outputting

Currently, I am converting TypeScript code to JavaScript for an application that is specifically targeting Node v.14. My goal is to have the output contain require statements instead of import statements. This is what my configuration file looks like: { ...

Using TypeScript with Mongoose: Issue with finding documents conditionally on model results in error: Union type signatures are not compatible

Seeking assistance on how to conditionally access a mongoose model in TypeScript code. Does anyone have a solution to resolve this TypeScript error? Each member of the union type has signatures, but none of those signatures are compatible with each other ...

What exactly is the function of the NextPage feature in Next.js?

Recently, I began incorporating TypeScript into my Next project. Could someone clarify the purpose of the following code snippets for me? import { NextPage } from 'next'; export const Page: NextPage = () => {} After reviewing the documentation ...

Discover the best way to showcase items within an arrayList using dual CSS styles!

I'm currently working on a project that involves an arrayList with two names: Bob and Steve. I have the requirement to display them in different colors, where Bob should be displayed in green and Steve in red. Component.CSS .Bob{ font-weight:bold; ...

Utilizing useLocation for Defining Text Styles

I'm currently integrating TypeScript into my project, but I'm encountering an error related to 'useLocation' in my IDE. Any thoughts on what might be causing this issue? import React from "react"; import { useHistory, useLocat ...

When attempting to compile Angular in production mode, errors may arise such as the Uncaught SyntaxError caused by an Unexpected token '<'

I encountered some errors in the console of my Angular 8 app. When I opened the browser window, it was blank and this error appeared: Uncaught SyntaxError: Unexpected token '<' I tried running different ng build commands such as: ng build --b ...

How can I use the Required utility type in TypeScript for nested properties?

I'm exploring how to utilize the Required keyword to ensure that all members are not optional in TypeScript. I've achieved success with it so far, but I've run into an issue where it doesn't seem to work for nested members of an interfa ...