Manipulating row content prior to or after pagination

Manipulating row content prior to or after pagination

robmiltonrobmilton Posts: 14Questions: 2Answers: 0

I have a table with rows that have a column containing a chart drawn with amCharts. When the pagination occurs and rows are "hidden" (rows that are not included in the current page) the charts in those hidden rows throw warnings. amCharts states that charts should be destroyed before being cleared/hidden in order to prevent memory leaks.

It's interesting to note that I do not get the warnings about the charts as a result of the "search" function filtering the rows. So fortunately it appears I don't have to address any issues with the "search".

For the pagination, however, I need to either only draw the charts for the rows that are displayed in the current page after the table has displayed the page... and then destroy those charts at the beginning of the next pagination event. Or draw the charts for ALL rows when the table is created but destroy the charts for the rows that are going to be hidden as a result of pagination.

Obviously it seems the first approach would be best since I'd be drawing significantly fewer charts if there are hundreds of rows on additional pages.

After reading through the available events and searching the forum (and Google in general) I haven't found an event/approach that clearly helps me accomplish my goals. Or maybe more specifically I haven't found any examples that show how to do what I need. This may be due to my lack of familiarity with good search terms related to my use case.

The "page" event states "event is fired when table's paging state changes". It seems like the "selector-modifier" with the "page" modifier used in combination with the "page" event may be headed in the right direction. But I'd really appreciate some guidance.

Any pointers/thoughts on what event(s) to use and how to approach this would be greatly appreciated!

Replies

  • kthorngrenkthorngren Posts: 21,126Questions: 26Answers: 4,916

    Without seeing what you have its hard to say specifically. My first thought is to use the predraw event or the to destroy the existing charts. I assume you are using one of the Datatables functions to build the chart for each table draw.

    It's interesting to note that I do not get the warnings about the charts as a result of the "search" function filtering the rows.

    Does seem odd.

    It seems like the "selector-modifier" with the "page" modifier used in combination with the "page" event may be headed in the right direction.

    Sounds like a reasonable approach to reduce the overhead of destroying and creating charts.

    I haven't used amCharts. Could you post a link to your page or build a test case so we can see what you have and how you are using amCharts? This will help us provide you with better answers.
    https://datatables.net/manual/tech-notes/10#How-to-provide-a-test-case

    Kevin

  • robmiltonrobmilton Posts: 14Questions: 2Answers: 0

    Hi Kevin,

    Thank you for your response and thoughts. I've created a test case to demonstrate what I'm doing and the warnings that are getting generated by amCharts when rows are hidden as a result of pagination.

    I'm sure the approach I'm taking to creating/populating the table and using DataTables is unconventional, but I'm new to DataTables and this is the best I've come up with so far. The site is a single page site so the DOM is being manipulated by JavaScript as the user chooses different content to view.

    So when the page containing this table is displayed I first clear and then destroy the DataTable holding this content. I then recreate the table in JavaScript, and once the table has been created (including the charts in each row) I then initialize the DataTable instance on the newly created table.

    If you take a look at the test case and open the developer's console by pressing the F12 key you'll see the warnings from amCharts about the charts that were hidden as a result of the pagination taking place. If you clear the console and then click the button to change to another page you'll get 10 more warnings which I believe are related to the charts from the previous page being hidden.

    What's interesting is that once you've paged through all of the available pages the first time subsequent visits to those pages don't generate the amCharts warnings.

    In any case I know that I simply need to call the "dispose" method on any visible charts before they get hidden/destroyed. So what I would like to do is create the table rows without including the charts. Then whenever rows are displayed (either as a result of pagination or searching) I'd like to generate the charts for the visible rows. Then when any action will cause a change in which rows are displayed I'd like first dispose of the existing/visible charts before the change in displayed rows followed by creating charts for whatever rows are ultimately displayed.

    I'd love help with what events to use (and how/when) in order to pursue this approach. Of course I'm also open to any other thoughts that make more sense as well!

  • kthorngrenkthorngren Posts: 21,126Questions: 26Answers: 4,916

    Thanks for the test case. This will be helpful. At a high level it looks like the problem is you are rendering the data and charts into the DOM then initializing Datatables. Datatales is re-rendering the data which is causing the Chart was not disposed id-22 messages. Let me look at this a bit.

    Does the data for the charts change while the table is displayed? The solution used will be determined by whether the data is static or changes.

    Kevin

  • kthorngrenkthorngren Posts: 21,126Questions: 26Answers: 4,916
    edited July 2020

    Ok, here is one solution that seems to work:
    http://live.datatables.net/focuhoba/2/edit

    I commented out the loop to add the rows directly to the DOM and used Datatables for this. It uses createdCell to create the chart div. This callback will need to change if your data can change. Maybe move it into the drawCallback rows().every() loop. It only executes once in createdCell.

    EDIT: Note the use of {page: 'current'} as the rows() selector-modifier so it iterates only the visible rows to create the charts.

    It uses the preDraw event to loop through the existing charts to dispose() of them.

    Let us know if this works for you.

    Kevin

  • robmiltonrobmilton Posts: 14Questions: 2Answers: 0

    Hi Kevin,

    This looks like a real possibility! The data will change frequently, so I definitely need to handle that. When you say to move the createdCell function into the drawCallback can you give me an idea of what this would look like? I get the concept, but the syntax and exact approach would be a great help!

    To update the data do I just set the "data" variable to the new data?

    Also, I'm assuming that when the data gets updated that I need to clear the existing data from the DataTable/table object before adding the new data. Where in the process and what specific call(s) should I use to do this?

  • kthorngrenkthorngren Posts: 21,126Questions: 26Answers: 4,916

    How do you plan to update the table. I mean is the user going to do something that updates one or some rows or are you going to reload all of the data? Or both?

    As before the answer will determine the solution :smile:

    Kevin

  • robmiltonrobmilton Posts: 14Questions: 2Answers: 0
    edited July 2020

    Sorry, I should have described that. In this case ALL of the data will be replaced as a result of JSON being returned from a call to retrieve the data from a SQL Server database.

  • kthorngrenkthorngren Posts: 21,126Questions: 26Answers: 4,916

    That's easy then. Use clear() followed by rows.add(). For example:
    http://live.datatables.net/gojupezu/2/edit

    See the button click event I added. Probable need to use dispose() on the existing charts.

    Kevin

  • robmiltonrobmilton Posts: 14Questions: 2Answers: 0

    Kevin,

    Thank you very much for all the assistance! I think this approach is going to work well. We have to make a few changes to our API in order to test this with many records (potentially in the neighborhood of 1000 rows). But testing with 20 or 30 rows this seems to work really well!

  • robmiltonrobmilton Posts: 14Questions: 2Answers: 0

    Unless I run into an issue when I'm able to test with a larger data set this discussion/topic has been "answered". Do I have the ability to mark this as answered? Or how does that work?

  • kthorngrenkthorngren Posts: 21,126Questions: 26Answers: 4,916
    edited July 2020

    Do I have the ability to mark this as answered?

    I don't think you used the "Ask a Question" button so the option isn't there. Its ok though.

    test this with many records (potentially in the neighborhood of 1000 rows).

    If you feel Datatables is initializing slow you can try the deferRender option to help increase initialization. Post back your results.

    Kevin

  • robmiltonrobmilton Posts: 14Questions: 2Answers: 0

    Hi Kevin,

    Thought I'd follow up with a small update. I discovered that I had to modify the approach. Since the site is a single page site the DOM is having content deleted/added based on user interaction. The table we've been working on actually gets deleted from the DOM when the user chooses to view other content. So I had to modify the approach to destroy the datatable any time the table is deleted from the DOM and then recreate the table in the DOM and re-initialize the datatable if the user chooses to view the table again.

    If there's a better approach I'd love to apply it...

    Still haven't had a chance to work with a large number of rows and the "deferRender" option. Will report back once I do.

    Thanks!

  • kthorngrenkthorngren Posts: 21,126Questions: 26Answers: 4,916

    I had to modify the approach to destroy the datatable any time the table is deleted from the DOM and then recreate the table in the DOM and re-initialize the datatable if the user chooses to view the table again.

    What happens, ie, why do you need to destroy the Datatable?

    Kevin

  • robmiltonrobmilton Posts: 14Questions: 2Answers: 0

    When the user chooses a different menu option the portion of the DOM containing the HTML table that holds this information is deleted. Then if the user chooses the menu item that displays the content that includes this table I recreate the table.

    If I don't destroy the DataTable then when the user comes back to the page that contains the (now new) HTML table the DIVs that held the charts have been deleted and amCharts can't find the DIVs in order to draw the charts.

  • kthorngrenkthorngren Posts: 21,126Questions: 26Answers: 4,916

    I see. Maybe using columns.render is a better option then. When redisplaying the table you can use rows().invalidate() to have Datatables use columns.render on the rows again. See this example:
    http://live.datatables.net/gojupezu/3/edit

    The console.log will show when columns.render runs.

    Kevin

  • robmiltonrobmilton Posts: 14Questions: 2Answers: 0

    It's not that the table is hidden. There is a DIV on the body used to display content selected in the menu by the user. The content of that DIV is cleared (div.innerHtml = '') and then new objects created in it whenever the user chooses a menu option. So it's not a display none/block issue. The table object is literally removed from the DOM.

  • kthorngrenkthorngren Posts: 21,126Questions: 26Answers: 4,916

    The same answer should apply. If it doesn't work then please update the test case to show the issue.

    Kevin

This discussion has been closed.