Refresh KnockoutJS Data In DataTables

2020-06-12 05:19发布

I have the following table

<table class="datatable zebra-striped">
    <thead>
        <tr>
            <th>Name</th>
            <th>Issue</th>
            <th></th>
        </tr>
    </thead>
    <tbody data-bind="foreach: Publications">
        <tr>
            <td><span data-bind="text: Name" /></td>
            <td><span data-bind="text: IssueNumber" /></td>
            <td><button type="button" class="btn" data-bind="click: $parent.DeletePublication">Delete</button></td>
        </tr>    
    </tbody>
</table>

Here is a snippet of the viewmodel:

function EditReaderViewModel() {
    var self = this;

    self.Publications = ko.observableArray([]);

    self.OnAddPublicationSaveButtonClicked = function () {
        //.. code omitted.    
        self.Publications.push(new Publication(publication.value, publication.label, publication.issueNumber));
    };
};

}

and the Publication object binded to the table:

function Publication(id, name, issueNumber) {
    var self = this;

    self.Id = id;
    self.Name = name;
    self.IssueNumber = issueNumber;
    self.LoadedFromDatabase = false;
}

When the data is first loaded into the table, and the datatable initialisation e.g.

$(".datatable").dataTable({ // blahh });

Everything works fine - the data is loaded in the table, sorting and filtering is working, etc.

Now when I add a new item to the Publications array in the viewmodel things just fall apart. For example, say I originally have 1 item in the Publications array, when I add another item, it will appear in the table until I click on a column heading to sort.

It seems that the datatable has it's own internal data list somewhere which does not include the new Publication I created.

Can someone guide me on how to rebuild the datatable, taking into account that the data is from a KnockoutJS viewmodel?

Please note that I have looked at this binding plugin:

http://www.joshbuckley.co.uk/2011/07/knockout-js-datatable-bindings/

The problem is that when I use this, I get error messages such as:

Requested unknown parameter '0' from the data source for row 0.

EDIT:

I'm looking through the code and I think I see the problem. In jQuery.DataTables.js there is this function function _fnGetCellData( oSettings, iRow, iCol, sSpecific )

In that function there is this line:

if ( (sData=oCol.fnGetData( oData )) === undefined )

which in turn calls:

function _fnGetObjectDataFn( mSource )

Now, in function _fnGetObjectDataFn( mSource ) there is this code which is called:

else
{
    /* Array or flat object mapping */
    return function (data) {
         return data[mSource];
    };
} 

data is not an array, it's a JSON object which means that the above code will fail (return data[mSource];).

I'm really not sure what to do here.

EDIT - IMPORTANT:

As one of the commentators has noticed, and I've just confirmed, accessing

http://www.joshbuckley.co.uk/2011/07/knockout-js-datatable-bindings

will result in a Trojan warning. So please be aware that this url is now an big NO-NO.

3条回答
做个烂人
2楼-- · 2020-06-12 05:31

You mention that you used datatable plugin and get "Requested unknown parameter '0' from the data source for row 0" error.

In my previous experineces using datatable without knockout plugin i got this error only using more columns than the header definitions or vice versa. You have to check your tbody and thead section and make it sure that both of them is the same size.

Or may be you are using "aoColumnDefs" option when you initialize the table.Again checked the option definiton and make sure that you havent try to reach unknown column :

For example if you have a definition like this

"aoColumnDefs": [{
         "bSearchable": false,
         "bVisible": false,
         "aTargets": [0]
     }, {
         "bSortable": false,
         "bSearchable": false,
         "sWidth": "45px",
         "aTargets": [2]
     }]

and if you have only 2 thead section this will give you that error. Because you are reaching third column with aTargets : [2]

查看更多
混吃等死
3楼-- · 2020-06-12 05:33

I was experiencing a similar problem as you've described here (and didn't have any intention of exploring the "bindings" link after the Kaspersky warning, even if it is really safe.)

Going a bit on the approach suggested here KnockoutJs - how to use datatables with existing bound table, I ended up taking a route where when using knockout on the table, I added a knockout if statement to test if the observableArray had at least one row of data.

<!-- if Publications.length() > 0 -->
<table class="datatable zebra-striped">
    <thead>
        <tr>
            <th>Name</th>
            <th>Issue</th>
        </tr>
    </thead>
    <tbody>
        <!-- ko foreach: Publications -->
        <tr>
            <td><span data-bind="text: Name" /></td>
            <td><span data-bind="text: IssueNumber" /></td>
        </tr>  <!-- /ko -->
    </tbody>
</table>
<!-- /ko -->

When loading the View Model, I then called the dataTables function inside my .ajax success function.

Then the other part to making it work was to make use of dataTables "bStateSave": true, so that any sorting I had done prior to a refresh would not be lost.

查看更多
干净又极端
4楼-- · 2020-06-12 05:36

I know that´s an older thread but since I found it when I had the same problem I feel the need to post the solution so others might find it quicker.

When refreshing the Table you can simple .clear() and then .destroy() the table. After that just reinitialize the table using the already known .DataTable()

Although that's a little messy because you really tear down the structure and rebuild it it work very smoothly.

You just have to add a boolean identifier you set to true the first time you initialize the table. And of course you have to bind the Table to a variable to be able to work the DataTable API magic on the DOM Element.

    if (managementLoadedDone){
            userTable.clear();
            userTable.destroy();
        }

Fill data in your Table

    userTable = $("#userTable").DataTable({responsive: true});
            usersLoaded = true;
查看更多
登录 后发表回答