.row(index).remove() not working as expected

.row(index).remove() not working as expected

getalexgetalex Posts: 39Questions: 11Answers: 1

I subscribed an array to add/delete events, so that the data table mirrors the operations visually.
The events trigger as expected, when I add/remove an item on the array, the code executes but the rows remain.

Example:

self.arrayItems.subscribe(function (changes) {
        for (var i = 0; i < changes.length; i++) {
            var item = changes[i];
            switch (item.status) {
                case "deleted":
                    var rowIdx = dt.column(1).data().indexOf(item.value.Id);
                    dt.row(rowIdx).remove();
                    break;
                case "added":
                    dt.row.add(item.value);
                    break;
            }
        }
        dt.draw(); // calling draw after for-loop
    }, null, "arrayChange");

Note: the "Add" function seems to work - on load, I get all items in the table and it shows up great, but they never get removed... I tried calling draw at the individual operation (i.e. dt.row(rowIdx).remove().draw(); and also tried to call invalidate().draw(); but no changes... also I tried to call dt.rows().invalidate().draw(); at the end of the for-loop with no luck.

Through debugging I verified that 'rowIdx' is in fact the row index I wish to remove, and dt.row(rowIdx).data() is the object being removed. Still the row remains after draw/redraw.

The workaround I found is to call dt.clear().draw() to completely remove all table rows, but then I have to re-load them all back in - I just want to remove one single row, and if I clear the array, it should be removing all the items through the delete change event - there's something I'm doing wrong here and I can't figure out why the rows aren't being removed.

Answers

  • getalexgetalex Posts: 39Questions: 11Answers: 1

    Here's a live demo I put together that works
    But for some reason in my solution code doesn't work - the problem I have is the remove is not executing as I expect it to, per the details above...

    http://live.datatables.net/vugilugo/2/edit?html,js,output

  • colincolin Posts: 15,240Questions: 1Answers: 2,599

    Hi @getalex ,

    Interesting that works on the fiddle, but not on your system. Are you seeing any errors before/after the non-remove? It would be worth running something like dt.rows().count() to see if the internal model has removed the row? Is your live sysem accessible - I could take a nose on there.

    Cheers,

    Colin

  • getalexgetalex Posts: 39Questions: 11Answers: 1

    Colin thank you for the prompt reply -- I don't have any way to share my system, it's an intranet, but the pattern I was following was borrowed from this example:
    https://datatables.net/dev/knockout/

    My takeaways after some testing throughout the day have been as follows:

    When I use an observableArray and subscribe it to changes (as the example link demo) and also I subscribe the datatable to changes such that it can invalidate a row and handle updates, I end up in a situation where performance takes a nosedive.

    I posted in another discussion that a page with about 500 items was taking almost 3 minutes to load. The culprit was a slow processing of "change" events that triggered at the data table & observable array coupled with several calls to "draw" … so I decided to scrap everything and try to implement my own approach ..

    I was able to achieve tremendously better performance BUT I don't like my solution. I'm basically duplicating efforts, I maintain the observableArray AND maintain the datatable rows - whenever I add an item to the array, I add it to the table. Sure, that's what was happening with the subscribe event example (see link again) but it seems more elegant to subscribe the array and datatable to listen in and update versus manually doing the heavy lifting each time an update happens.

    Here's some sample code that works albeit being redundant:

    // get the observable array item and update it
    var itemIndex = viewModel.arrayItems().indexOf(updateItem);
    var arrayItem = viewModel.arrayItems()[itemIndex];
    
    arrayItem.Status(updateItem.Status);
    
    // get the datatable row item and update it
    var rowIdx = dt.column(1).data().indexOf(updateItem.Id);
    var rowItem = dt.row(rowIdx).data();
    
    rowItem.Status(updateItem.Status);
    dt.row(rowIdx).invalidate(); // redraw the updated row
    
    // if I'm deleting the row I delete it twice, for example
    viewModel.arrayItems.remove(arrayItem);
    dt.row(rowIdx).remove().draw();
    
    

    There absolutely has to be a better (or more elegant) way to implement this solution. This is the only way I found that works and keeps performance acceptable. Any feedback on this (specifically reviewing the link I shared on knockout integration) would be great - as I mentioned, the link appears to work for demo purposes but it would be good to know if anyone can confirm the performance issues I ran into, and also the issues where rows weren't removed at all even with the events triggered.

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin

    Performance was the reason I never took that Knockout integration for DataTables any further - the observables are horribly slow and that is really noticeable when you have a reasonable number of them. You can speed things up a little if you just have the main array as observable and not the contents of each row, but then you are loosing half of the functionality.

    The duplicating of state is, as you say, redundant. For that reason, whenever I've needed to do this myself, I've just used DataTables as the data source rather than Knockout. That doesn't always fit I know, and perhaps there is a better way to do it - but I'm not particularly well versed in Knockout I'm afraid.

    Allan

  • getalexgetalex Posts: 39Questions: 11Answers: 1

    Allan - thanks for the feedback, the update redundancy is steep but I need to maintain the observable array as it's used in other dependencies ... there ought to be a better way to do this, so I'll see if I implement my own mapping or test some alternate approach that performs better.

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin

    Interested to hear how you get on with it!

    I've been meaning for a while to use Javascripts own native observable objects as well and see how they perform. Should be a lot quicker than Knockouts'.

    Allan

  • getalexgetalex Posts: 39Questions: 11Answers: 1

    For the time being I’ve ripped/replaced the underlying observableArray and use the DT as the collection of reference. When a dependency needs an observable array I map a helper method to build and return it or another helper merhod to use as the datasource and reload the DT if that’s needed, but I avoid at all costs the dual change subscriptions (array change and dt row value change)

This discussion has been closed.