[Data Grid Reactive] Add functionality to maintain rows highlight across pagination in data grid reactive
Forge component by OutSystems R&D
Application Type

Good time of the day,

I'm using the Data Grid Reactive component and I'm supplying it with a JSON string to dynamically create the table grid (screenshot below). The number of columns may vary every time the table is built based on the page parameters. I'm trying to highlight rows and retain the highlights even when using pagination. We're using row highlighting to let users select and manipulate rows. Is there any way to do this? Alternatively, is there a way to add a checkbox column to a dynamically generated table?




Hi Sergei Gushchyn,

I hope you are safe and well.

You can hide whatever you want to in this table. You can do this with the help of IF widget. In if widget you need to put condition accordingly.

This will help you out.


Supriya Madkar.

Hi Sergei Gushchyn,

 I hope you are safe.

You Can add checkbox by dragging the checkbox widget  in the column you want, and give the source of your attribute. It will Add Checkbox in the table column.

This will help you.

Thanks and Regards.

Rajeshree Chhablani.

Hello Rajeshree Chhablani,

Thank you for your reply. The solution that you described would work if I would define columns and data types in Service Studio. But all the columns are dynamic. All I'm supplying for widget is a JSON string.

Hi , 

Good Evening 

If you want to create widget dynamic then you need to write html code in logic , and whatever Value is in JSON you need to assign in Checkbox.

Thanks and Regards.

Rajeshree Chhablani. 

Got a solution. Grid API provide access to the rows that are displayed on the current page ( GridAPI.GridManager.GetGridById($parameters.GridId).provider.rows; ), and GetSelectedRowsData action allows to have access to the selected rows. I loop through those rows and compare a unique parameter. If the current page has a row that matches a selected row I change the property of that row on the current page to isSelected = true (which gives me a required highlight). In order to trigger those events I added event listeners to pagination buttons "onclick" and added event listener to the search widget "keydown".

Hello @Sergei Gushchyn ,

We are interested in understand this requirement despite you have been have to solve it by yourself.

Are you storing in a list a unique key chosen by you, getting the selected rows using GetSelectedRowsData before you change page?

Is your solution working for column sorting and column filtering?

Please let us know some more details.


Bruno Martinho

Hello @Bruno Martinho,

Yes, the solution works with filtering and sorting of the grid. It is more complex than the one I have described in my reply above. I will try to use a simple example in order to show why we needed that functionality, and how the solution was built. I admit that I could built a more efficient solution if I knew how to use HashMap in OutSystems.

In our tool we use grid as some sort of a catalog. For example, I have a user, and I want to assign them as an editor to a certain list of resources. So the grid will have those resources. But since the number of columns for each case is dynamic, we couldn't predefine those columns. 

Let's say we have 3 pages with rows [1, 2, 3, 4, 5], [6, 7, 8, 9, 10], and [11, 12, 13, 14, 15]. The user chooses rows 2 and 3 on the first page. With API GetSelectedRowsData, I can get the data of those selected rows. Once the user goes to the next page and selects rows 7 and 8, GetSelectedRowsData will have data only for 7, and 8. So, I implemented a new variable TotalRowsData (type: RowData List). I created a function that runs when a certain events is triggered like "next page". This function copies rows from GetSelectedRowsData to TotalRowsData. I added this function as a handler to grid._features.pagination._view.pageChanged._handlers.push({handler: myFunction}). Now the problem was if the user goes back to the first page to check their selection, it would not show rows 2 and 3, even though they are in my total list. In this case right after I add selected rows to total, I call API grid.provider.rows. This value contains all the rows on the current page. So, I loop through all the rows on the current page, and compare them to TotalRowsData list. There is a field that is not ID, but unique to each row. Once I found a match of that field, I change the current row attribute isSelected to True, and it will highlight rows 2 and 3. 

Now the problem was that if the user found out that instead of row 2, they had to choose row 4, they had to  unselect row 2, and select row 4. Now I couldn't just append selected rows to total because it would create a duplicate for row 3, and row 2 would still be in total. There was no way to identify that row 2 was unselected. API only provides data about selected rows. So I implemented a variable TempRowsData (type: RowData List). I store there rows that were highlighted/selected during the loop. In our case temp list had rows 2 and 3, when user went back to the first page. I had an onClick listener on a grid container. So when row 2 unselected that triggers an event that calls a function. In that function I remove temp list from total list and I append total to the list that is returned from GetSelectedRowsData, in other words 2 and 3 were removed from total, it became 7 and 8. The only row that was selected on the first page was 3, so appended 7 and 8 to 3. Once the user selected 4, GetSelectedRowsData had rows 3 and 4. So I appended 7 and 8 to 3 and 4. Once the user clicked on the next page I called the function I described above, and copied 3, 4, 7, and 8 to total. So total now was 3, 4, 7, 8. On the second page, rows 7 and 8 were highlighted, and temp list had become 7 and 8.

With search I added event listener to the input. searchInput.addEventListener("keydown", myFunction). Every time a new key is entered it loops through the list of all the rows on a current page and compares it to total list. If any match found, it will highlight it. If new selection is made, it will follow the same logic as described above.

For filter I added the same handler as I did for "page change" event. grid._features.filter._filter.filterApplied._handlers.push({handler: myFunction}). So that when filter is applied the same function that compares all the rows on a current page with total rows is called. If a new selection is made it follows the same logic as described above.

For sort, it was a bit complicated because I had an onClick event listener for the grid, and when user would click on sort, it would trigger function as of new selection was made. In order to avoid this, I check for event target class name to make sure that new selection is triggered only when user clicks on the left side headers of the grid. For the sort I call the same function that compares all the rows on a current page to the total rows. There was only one exception. I used 300 ms delay for sort because it would render rows for the current page a bit slower then it would do for filter or search.

Hope it helps. Let me know if you have any questions.

Thanks for such a detailed explanation.

I'll try to reproduce this on our side and if we find a way to achieve this easier, we'll let you know!

Thanks again!

Bruno Martinho

Community GuidelinesBe kind and respectful, give credit to the original source of content, and search for duplicates before posting.