Primeng: Datatable selection detection can not work if its value is immutable object array

Created on 8 Dec 2016  路  18Comments  路  Source: primefaces/primeng

I'm submitting a ... (check one with "x")

[x] bug report => Search github for a similar issue or PR before submitting
[ ] feature request => Please check if request is not on the roadmap already https://github.com/primefaces/primeng/wiki/Roadmap
[ ] support request => Please do not submit support request here, instead see http://forum.primefaces.org/viewforum.php?f=35

Plunkr Case (Bug Reports)
Please fork the plunkr below and create a case demonstrating your bug report. Issues without a plunkr have much less possibility to be reviewed.

http://plnkr.co/edit/NtWWnN

Current behavior

I use ngrx in my ng2 app, I also freeze the store so any value in store is immutable. When I pass p-dataTable a object array and select a row, it cause a exception: Can't add property _$visited, object is not extensible.

Expected behavior

Datatable selection detection can work if its value is immutable object array

Minimal reproduction of the problem with instructions

What is the motivation / use case for changing the behavior?

Please tell us about your environment:

  • Angular version: 2.0.X

  • PrimeNG version: 1.0.1

  • Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]

  • Language: [all | TypeScript X.X | ES6/7 | ES5]

  • Node (for AoT issues): node --version =

enhancement

Most helpful comment

I've added dataKey property to support this also increase performance. See #2356

<p-dataTable [value]="cars" selectionMode="single" [(selection)]="selectedCar" dataKey="vin">
    <p-column field="vin" header="Vin"></p-column>
    <p-column field="year" header="Year"></p-column>
    <p-column field="brand" header="Brand"></p-column>
    <p-column field="color" header="Color"></p-column>
</p-dataTable>

When dataKey is present DataTable uses this key if a row is selected or not. This increases performance as it avoids traversing all properties of two compared objects and also supports immutable objects. For example, it should even work if you run Object.freeze() on all rows.

All 18 comments

+1

would love to see support for:

  1. async pipe
  2. immutablejs data classes

@liubiggun I am evaluating datatable and I am also using ngrx. Have you decided not to use datatable or are you bypassing ngrx and use mutable data?

for now the workaround is:

import {Pipe, PipeTransform} from '@angular/core';
import {Map, List} from 'immutable';
import {StoreModel} from "../store/model/StoreModel";
@Pipe({
    name: 'ListToArrayPipe'
})
export class ListToArrayPipe implements PipeTransform {
    transform(items: List<StoreModel>, ...args: any[]): any {
        var arr = items.toArray();
        return arr;
    }
}

public campaigns$: Observable<List<CampaignsModelExt>>;

<p-orderList [responsive]="true" [value]="campaigns$ | async | ListToArrayPipe">

@born2net that workaround does not solve the issue with ngrx.

The ngrx mentality is to treat all values as if they are immutable. Application state in an ngrx application is updated by replacing any existing values with new values instead of modifying existing values. The new values may be modified clones of the previous values, but after that they can never be modified.

This programming style can be enforced by using ngrx-store-freeze in your ngrx project. As mentioned, any attempt to modify the current state will result in an error being thrown by ngrx-store-freeze.

All this means that it is impossible to use values from the ngrx store in a DataTable that has selectionMode enabled because the DataTable treats your values as mutable. It mutates YOUR objects to track its OWN internal state. That is pretty disgusting in my opinion.

I'm starting to think this problem has been fixed in a recent version because I can't reproduce this myself. To reproduce this problem, set the selection mode to 'single', run Object.freeze() on all rows and then try to select a row.

I agree, not a solution but a workaround to be able to use the component

This issue is bigger than not being able to use immutable collections. With ngrx, every collection is immutable but every collection item is also immutable.

I'd like to know if immutable data structures are now supported in the latest version. I used to have the same problem as @liubiggun but now I can't reproduce the error after updating.

@StevenLiekens I am using 2.0.1 at the moment and I don't see the error anymore. But I remember seeing it at some point... Btw, highcharts have the same problem. The idea of the workaround is to treat the grid component as a dumb component and using cloned data instead of the true source.

Anyways, primeng datatable is very slow for large datasets. I am going to remove it from my project for now. Hopefully it'll get faster in the coming releases...

@PierreRochard I only read the description but I'm guessing that is a completely different issue.

We're only talking about the feature that lets the user select rows by clicking them. This feature has a nasty side effect of attaching properties to objects that are selected. I assume it does this to keep track of which rows are selected. This breaks when the row objects are frozen objects.

At least that's how it used to be. Me and others are no longer observing this behavior in the latest version.

@StevenLiekens Odd. I'm still observing this behavior with PrimeNG 2.0.4 and ngrx-store-freeze.

I've added dataKey property to support this also increase performance. See #2356

<p-dataTable [value]="cars" selectionMode="single" [(selection)]="selectedCar" dataKey="vin">
    <p-column field="vin" header="Vin"></p-column>
    <p-column field="year" header="Year"></p-column>
    <p-column field="brand" header="Brand"></p-column>
    <p-column field="color" header="Color"></p-column>
</p-dataTable>

When dataKey is present DataTable uses this key if a row is selected or not. This increases performance as it avoids traversing all properties of two compared objects and also supports immutable objects. For example, it should even work if you run Object.freeze() on all rows.

be awesome if we could have an example in the docs with ImmutableJS,
tx as always,
Sean.

Sure, will do.

how about sorting?
It also seems not to be working with immutable objects. I get error:
Cannot assign to read only property '1' of object '[object Array]'
at Array.sort (native)
at Array.sort (http://localhost:4200/polyfills.bundle.js:4982:15)
at DataTable.sortSingle (http://localhost:4200/vendor.bundle.js:122420:28)
at DataTable.sort (http://localhost:4200/vendor.bundle.js:122400:26)
.....

Please create another issue for this.

I just updated to PrimeNG 4.0.0 and can confirm that using the new dataKey option fixes the problem.

Glad to hear.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

markgoho picture markgoho  路  3Comments

mitosandov picture mitosandov  路  3Comments

papiroca-tm picture papiroca-tm  路  3Comments

jisqaqov picture jisqaqov  路  3Comments

SchneMa picture SchneMa  路  3Comments