Search code examples
javascriptknockout.jsknockout-mapping-plugin

How to sort data bind to table using knockoutjs mapping plugin?


I am able to bind data to a table and sort using the column headers.

However, I need to be able to edit the data so that it is updated and reflected in the corresponding table cell. To do this I need to make the data object an observable.

Instead of binding like this, using text binding:

<tbody data-bind="foreach: countries">
<tr>
    <td data-bind="text: name"></td>
    <td data-bind="text: capital"></td>
    <td data-bind="text: population"></td>
</tr>
</tbody>

I need to bind using the value or textInput binding. Like so:

<tbody data-bind="foreach: countries">
<tr>
    <td><input data-bind="value: name" /></td>
    <td><input data-bind="value: capital" /></td>
    <td><input data-bind="value: population" /></td>
</tr>
</tbody>

And instead of doing this:

        $.getJSON('https://restcountries.eu/rest/v1/all', function(data){
            self.countries(data);
        });

I do this:

        $.getJSON('https://restcountries.eu/rest/v1/all', function(data){
            var mappedData = ko.mapping.fromJS(data);
            var array = mappedData();
            self.countries(array);
        });

If I attempt to mapped the data using the plugin, the sort does not work.

How do I mapped the data as observables and still have the capability to sort them?

Here is a working JSFiddle example: Note: I removed the mapping since it breaks the code.


Solution

  • I checked the fiddle, the mapping plugin that you linked is wrong. The one in github is not supposed to be a cdn.

    Remove the mapping plugin link you added and change it to this link.

    I also forked the fiddle with the correct url and added the lines that you removed.

    var mappedData = ko.mapping.fromJS(data);
    var array = mappedData();
    

    EDIT:

    To fix the sorting, you need to change your sorting functions to call the observable values and not the observable function. Like from:

    Excerpt from stringSort function:

    var countryA = a[column.property].toLowerCase(), countryB = b[column.property].toLowerCase();
    

    to:

    var countryA = a[column.property]().toLowerCase(), countryB = b[column.property]().toLowerCase();
    

    You also need to modify the numberSort, dateSort, and deepGet (which is used in objectSort) for other sorts to work. Please check updated fiddle for the sample changes.

    JSFiddle link.