Search code examples
jqueryknockout.jsknockout-2.0knockout-mapping-plugin

How to convert json string to ko.observableArray([]), they get an error data is not defined?


I am new to knockout js, I create a table of data display with knockout framework and ajax call. I have Problem with the observable array should not get the values and display in table. My code is :

$(function() {

var RacerModel = function() {   
    self.Categories = ko.observableArray([]);
    self.Message = ko.observable("Data don't loaded");
    self.GetCategories = function () {
        $.ajax({
            url: "data1.json",
            cache: false,
            type: "GET",
            datatype: "json",
            contenttype: "application/json;utf8"
        }).done(function (data) {//self.Categories(ko.mapping.fromJS(data));
        }).error(function (err) {
            self.Message("Error! " + err.status);
        });
    }
    console.log(JSON.stringify(data));

};

ko.applyBindings(RacerModel());

});

JSON File is :

{"categories":[{"Id":1,"Name":"Learning","UrlSlug":"0-learning","Description":"learning"},
{"Id":2,"Name":"Topics","UrlSlug":"0-topics","Description":"posts"},
{"Id":3,"Name":"Shares","UrlSlug":"category-shares","Description":"shares"},
{"Id":4,"Name":"Projects","UrlSlug":"category-projects","Description":"project"}]}

The Problem is self.Categories = ko.observableArray([]); do not bind the value. It is always empty, and got error like data is not defined. How to get ko.observableArray([]) has an value through json method.

My sample html code is :

<tbody data-bind="foreach: Categories">
    <tr>
        <td><span data-bind="text: Name"></span></td>
        <td><span data-bind="text: UrlSlug"></span></td>
        <td><span data-bind="text: Description"></span></td>
    </tr>
</tbody>

Solution

  • This would be the correct way to use the mapping function:

    ko.mapping.fromJS(data.categories,{}, self.Categories);
    

    See why over here.

    var RacerModel = function() {   
        self.Categories = ko.observableArray([]);
        self.Message = ko.observable("Data don't loaded");
        self.GetCategories = function () {
            //$.ajax({
            //    url: "data1.json",
            //    cache: false,
            //    type: "GET",
            //    datatype: "json",
            //    contenttype: "application/json;utf8"
            //}).done(function (data) {
            //self.Categories(ko.mapping.fromJS(data));
            //}).error(function (err) {
            //    self.Message("Error! " + err.status);
            //});
            ko.mapping.fromJS(data.categories,{}, self.Categories);
            
        }
        var data = {"categories":[{"Id":1,"Name":"Learning","UrlSlug":"0-learning","Description":"learning"},
    {"Id":2,"Name":"Topics","UrlSlug":"0-topics","Description":"posts"}, {"Id":3,"Name":"Shares","UrlSlug":"category-shares","Description":"shares"}, {"Id":4,"Name":"Projects","UrlSlug":"category-projects","Description":"project"}]};
    
    };
    
    ko.applyBindings(RacerModel());
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
    
    <!-- ko if: Categories().length > 0 -->
    <table>
    <tbody data-bind="foreach: Categories">
      <tr>
        <td><span data-bind="text: Name"></span></td>
        <td><span data-bind="text: UrlSlug"></span></td>
        <td><span data-bind="text: Description"></span></td>
      </tr>
    </tbody>
    </table>
    <!-- /ko -->
    
    <button data-bind="click: GetCategories">Get data</button>