Handling big data on DataTable with checkbox selection / MultiSelect
Tags: primeng, primevue, primereact, performance
Published: 2023-12-14 09:48:25

In this article, I will delve into how DataTable and MultiSelect components of Prime{NG|Vue|React} can be effectively utilized with checkbox selection features and how performance can be improved. I will try to explain this through DataTable, which is widely used and contains many features. Let's get started!

> **Note**: If you lack basic knowledge about the DataTable component and its features, I recommend checking the documentation on [PrimeNg](https://primeng.org/table), [PrimeVue](https://primevue.org/datatable) and [PrimeReact](https://primereact.org/datatable) before proceeding.

Nowadays, almost every DataTable component incorporates a selection feature, catering to diverse user experiences. Prime libraries stand out in this regard, offering advanced modes, among which checkbox selection is a notable example.

An example from [PrimeVue](https://primevue.org/datatable/#checkbox_row_selection);
```html
<DataTable :value="data" dataKey="id" v-model:selection="selectedItems">
    <Column selectionMode="multiple"></Column>
    // other columns
</DataTable>
```
When we examine this code, the crucial point in it is the `dataKey` property. When a checkbox in a row is clicked, this property searches from the `selectedItems` list to determine if that data has been selected before, based on the provided field name. As you know, there are many ways to detect whether two objects are the same, and the way Prime libraries recommend is to do this by using `dataKey` property. This is the most efficient way to decide whether the objects are the same. Perhaps the main question is, is just using `dataKey` always enough? The answer would be yes if you have small data, but if you are working with a large dataset, it will not be enough. So what should I do? Splitting the data is the best approach. DataTable has powerful features in this regard, such as `paginator`, `virtualScroller` and `lazy`. These features both increase the rendering time of the DataTable and provide solutions for such selection problems. Maybe I can discuss these in more detail in another article, but I need to briefly touch on these features to explain the checkbox selection feature better.

- [Paginator](https://primevue.org/datatable/#paginator) divides data into groups, displaying them page by page.

- [VirtualScroller](https://primevue.org/datatable/#virtualscroll) separates data based on row height, loading them as the DataTable is scrolled.

- [Lazy](https://primevue.org/datatable/#lazy_load) processes data with callbacks to control some features of the DataTable. It does not know what data it will process next viewport. According to the information in the callbacks, you need to prepare the data that your DataTable will process. It allows us to use DataTable with larger and dynamic datasets with better performance.

These features can be used independently or combined, with `lazy` and `paginator` being a popular combination among Prime users. These features enhance the rendering time of the DataTable, but what will happen when the dataset of the DataTable is selected using the header checkbox? For `virtualScoller` and `lazy`, only the data in the viewport will be selected. With the `paginator`, the whole dataset will be selected and this will be quite slow. We have overcome the rendering time problem, so what should we do now? It's finally time to introduce the `selectAll` property and `selectAllChange` callback. This gives you the authority to control the selection completely using the header checkbox. Thanks to these features, the DataTable skips all controls which decide to select or unselect the dataset. Then, you should decide what will happen when the header checkbox is clicked.

An example from PrimeVue;
```html
<DataTable :value="dataset" dataKey="id" v-model:selection="selectedItems"
    :selectAll="selectAll" @select-all-change="onSelectAllChange" @row-select="onRowSelect" @row-unselect="onRowUnselect">
    <Column selectionMode="multiple"></Column>
    // other columns
</DataTable>
```

```js
<script setup>
import { ref, onMounted } from 'vue';

onMounted(() => {
  // load dataset
});

const dataset = ref([]);
const selectedItems = ref([]);
const selectAll = ref(false);

const onSelectAllChange = (event) => {
  if (event.checked) {
    selectAll.value = true;
    selectedItems.value = // all data according to your needs 
  } else {
    selectAll.value = false;
    selectedItems.value = [];
  }
};

const onRowSelect = () => {
  // This control can be completely managed by you.
  selectAll.value = selectedItems.value.length === totalRecords.value;
};

const onRowUnselect = () => {
  // When a row is unchecked, the header checkbox must always be in an unchecked state.
  selectAll.value = false;
};
...
</script>
```
Why doesn't dataTable do all these checks? DataTable does check when you do not use the `selectAll` property. However, these checks can be very slow on large datasets. In order to explain this part better, I will need to explain a little about DataTable and the problems faced by users. DataTable never mutates your dataset and stores it somewhere. Therefore, in every data change or action such as sorting and filtering, the original dataset is used and the target dataset is created. I mentioned above what needs to be done to improve this process. When you want to select the entire dataset using the header checkbox, it is necessary to determine whether the entire dataset is in the `selection` list. This is costly. So why can't DataTable decide whether all the data is selected by checking the lengths of the datasets and selections as above? The answer to this question is quite simple. DataTable doesn't know whether the data has changed or not. You may have changed the data in the selection and the data in the dataset at a certain time. Or you can set certain data in the dataset to be disabled or unselectable in the DataTable. This may be one of the most used structures. Especially in PrimeReact, you can decide whether or not to have checkboxes in rows based on certain conditions using certain methods. When you consider many more possibilities like this, DataTable cannot do this by just comparing length. The length control example above is given to show that it is a condition completely determined by the user. In the real world, not everything is this simple, a UI component must consider every possibility and act accordingly. Of course, I'm not saying you shouldn't use the length comparison. This completely depends on your app and dataset. 

Now, let's address some frequently asked questions to enhance understanding:

#### [💭](#checkbox-lazy-paginator) <a id="checkbox-lazy-paginator" />DataTable in my application has checkbox selection, lazy and paginator features. When I select all data using the header checkbox, the data on the next page is not selected. How can I overcome this?
> 🔒 _Test cases; [PrimeReact](https://stackblitz.com/edit/react-hh2aau-16vcfu?file=src%2FApp.js) | [PrimeVue](https://stackblitz.com/edit/tq4cbz-h8ymrp?file=src%2FApp.vue) | [PrimeNg](https://stackblitz.com/edit/angular-at-yaac26?file=src%2Fmain.ts)_

✨ DataTable does not mutate data and when it has the `lazy` property, everything has to be controlled by the user. In this question, DataTable with the `lazy` property does not know what the data will be on subsequent pages. That's why it can't add them to the `selection` list. When you go to the next page, since there is no current data in the `selection` list, all of them are unchecked. The solution to this problem is to either set all data to the `selection` list using the `selectAllChange` callback or to add the data that will be displayed in the callback when the page changes to the `selection` list. I would recommend the former, because you may want to use the `selection` list without making any page changes. In this case, you will have the actual selected values.
> 🔐 _Recommended uses; [PrimeReact](https://stackblitz.com/edit/react-hh2aau-s9zqgh?file=src%2FApp.js) | [PrimeVue](https://stackblitz.com/edit/tq4cbz?file=src%2FApp.vue) | [PrimeNg](https://stackblitz.com/edit/angular-at-yx2f5y?file=src%2Fmain.ts)_

---

#### [💭](#checkbox-lazy-paginator) <a id="checkbox-lazy-paginator" />DataTable in my application has checkbox selection and virtualScroller. Even though I select all the rows one by one, the header checkbox does not appear checked. Also, when I click on the header checkbox, data selection is very slow. How can I overcome this?
> 🔒 _Test cases;_ [PrimeReact](https://stackblitz.com/edit/react-omewwn?file=src%2FApp.js) | [PrimeVue](https://stackblitz.com/edit/9ywajd?file=src%2FApp.vue) | [PrimeNg](https://stackblitz.com/edit/angular-at-2hwjh3?file=src%2Fmain.ts)

✨ This is similar to the previous question. The only difference is that in the preloaded `virtualScroller` feature, checking the entire dataset and updating the header checkbox is slow. In some cases, when users check and uncheck the header checkbox very quickly, they cannot realize whether this happened or not. In such cases, the best approach is to use the `selectAll` property and `selectAllChange` callback. 
> 🔐 _Recommended uses; [PrimeReact](https://stackblitz.com/edit/react-omewwn-zqpe5m?file=src%2FApp.js) | [PrimeVue](https://stackblitz.com/edit/9ywajd-dnq98z?file=src%2FApp.vue) | [PrimeNg](https://stackblitz.com/edit/angular-at-pcfxy1?file=src%2Fmain.ts)_

---

#### [💭](#checkbox-condition) <a id="checkbox-condition" />I want to use the header checkbox in the DataTable to select data according to a certain condition. How can I achieve this? 

✨ As a UI, you can hide or disable the checkbox of certain data using CSS. For example, PrimeReact has an `isDataSelectable` prop to decide this. Assuming that you have done this somehow, you can set it to True or False according to the condition you specify by using the `selectAll` property. You can also add data to the `selection` list by filtering the data, just like you did with a disabled or condition. In such cases, it would be wrong to compare the lengths of the dataset and the `selection` list, as mentioned above.
> 💡 _Example; [PrimeReact](https://stackblitz.com/edit/react-hh2aau-j7brid?file=src%2FApp.js) | [PrimeVue](https://stackblitz.com/edit/tq4cbz-tteow9?file=src%2FApp.vue) | [PrimeNg](https://stackblitz.com/edit/angular-at-6hsnzb?file=src%2Fmain.ts)_

---

These questions address common challenges encountered in Prime libraries. I hope this article provides valuable insights, guiding you to make informed decisions when using DataTable with the checkbox selection feature. Your opinions and suggestions are very valuable, so please do not hesitate to share them with us. I want to create an article series based on my experiences on these and similar frequently asked questions or the decisions made by Prime libraries in their updates.

Happy coding!




​