I have a datatable, chart, and Latest value added label.
I have issue with editing the rows. So when i click edit and type something in the input (only numbers) and then click cancel edit (X) the values gonna get changed in the table and chart after the 10 seconds. Which it shouldnt since i cancel the edit. Same thing when i type in the input and just wait without saving the edit or canceling, the values gonna get changed.
I think it’s something with the two way binding in the table but not sure how to fix
I tried doing this but same result:
clonedData = [];
ngOnChanges() {
this.clonedData = [...tableData]}
and then in html table for the value i passed clonedData instead of tableData
here is stackblitz link : 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 ts
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
<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>
[Note: most examples for the PrimeNG are not paired with live chart, so they don't actually cover your use-case, and that's why you're having issues if you're following those tutorials.]
Yes, the problem is in binding: you're binding the time/value to an actual table data, so whenever you edit it - regardless of accepting or cancelling changes - you're effectively changing the original table data. So, you should bind to other variables. I've edited your stackblitz code with these changes:
idBeingEdited
, timeBeingEdited
and valueBeingEdited
and bound them in template [table.comp.html] instad of data.time
and data.value
. That way we're keeping the 'original' data (particularly important for the order of rows) intact and working only with these local/bound values.onRowEditInit()
method to set the values of these variables to the actual data being edited.onRowEditCancel()
method, because now we're working with non-original data and no changes (in logic or data) will need to be made if you just cancel the operation.editRow()
method - removed parameters (because we don't need template data here: we have local bounded values) - to change only the original data at the required id, so that nothing else changed.So, 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);
}
and in table.comp.html:
<input pInputText type="text" [(ngModel)]="data.time" />
becomes <input pInputText type="text" [(ngModel)]="timeBeingEdited" />
<input pInputText type="number" [(ngModel)]="data.value" />
becomes <input pInputText type="number" [(ngModel)]="valueBeingEdited" />
(click)="editRow(data, ri)"
becomes (click)="editRow()"
Here's a stackblitz demo.