0

I try to connect my REST server with JavaScript app. Using ajax query I get proper JSON, but I cannot bind it to my HTML website. I use data-bind in HTML:

<tbody>
  <tr >
    <td> <input type="number" data-bind="value: index" name="index" readonly>  </td>
    <td> <input type="text" data-bind="value: name" name="name"required> </td>
    <td> <input type="text" data-bind="value: surname" name="surname"required> </td>
    <td> <input type="date" data-bind="value: birthdate" name="birthdate" min="1950-01-01" max="2050-01-01" required> </td>
    <td><button type="button" >Edit</button></td>
  </tr>
</tbody>

In .js file I have below code:

'use strict';

var URL = 'http://localhost:8000/'

$(document).ready(function(){

var StateViewModel = function () {
    var self = this;
    self.students = ko.observableArray();

    $.ajax({
        url: URL + 'students',
        type: 'GET',
        dataType: 'json',
        accepts: {
            contentType: 'application/json'
        }
    }).done(function(result) {
        console.log(result)
        ko.mapping.fromJS(result, self.students);
    });
}

var model = new StateViewModel();
ko.applyBindings(model);

});

And I get "ReferenceError: index is not defined" error.

When I request my REST appI get below JSON:

[
{
    "index": 127001,
    "name": "John",
    "surname": "Smith",
    "birthdate": "1996-11-11"
},
{
    "index": 127002,
    "name": "Abcd",
    "surname": "Xyz",
    "birthdate": "1996-11-01"

}
   ]

And in ajax function .done result is:

0: Object { index: 127001, name: "John", surname: "Smith", … }
1: Object { index: 127002, name: "Abcd", surname: "Xyz", … }

What could be the reason of "ReferenceError: index is not defined" error?

Kate
  • 3
  • 1
  • 3
  • What exactly is `ko` – Isaac Vidrine May 24 '19 at 20:04
  • ko is knockout.js – Kate May 24 '19 at 20:07
  • https://knockoutjs.com/documentation/observables.html – Kate May 24 '19 at 20:08
  • From what I see, `ko.mapping.fromJS` only takes two params at most, and you're passing it 3, the 2nd being an empty object... why is that? – Isaac Vidrine May 24 '19 at 20:11
  • without it I have the same problem – Kate May 24 '19 at 20:12
  • Looks like you need to read the documentation better. `ko.mapping.fromJS` expects a data set and a view model, but instead of a viewModel you are passing it an observable array. – Isaac Vidrine May 24 '19 at 20:15
  • https://knockoutjs.com/documentation/plugins-mapping.html – Isaac Vidrine May 24 '19 at 20:16
  • using viewModel like that: ''' var myViewModel = { index : ko.observable(index), name : ko.observable(name), surname : ko.observable(surname), birthdate : ko.observable(birthdate) } ''' and apply it like that: ko.mapping.fromJS(result, myViewModel); I still have index is not defined" problem – Kate May 24 '19 at 20:19
  • Do you have a `data-bind="foreach: students"` somewhere? Without one your context is the root view-model which doesn't have an "index" property. – Jason Spake May 24 '19 at 20:51

3 Answers3

0

Taken straight from the docs

The first time you fetch data you should do this

var viewModel = ko.mapping.fromJS(data);

Then every time data is received from the server after that

ko.mapping.fromJS(data, viewModel);

Isaac Vidrine
  • 1,568
  • 1
  • 8
  • 20
0

Your JSON looks fine, and there's nothing wrong with using 3 arguments for your mapping.fromJS with an empty object as the "options" argument. My guess is that it's a context issue with which object your markup is attempting to bind to. If you're still at the root level view-model the binding will fail because "Index" doesn't exist at the root level. You need a foreach binding to nest into the "students" child object.

var URL = 'http://localhost:8000/';
var sampleData = [{
    "index": 127001,
    "name": "John",
    "surname": "Smith",
    "birthdate": "1996-11-11"
  },
  {
    "index": 127002,
    "name": "Abcd",
    "surname": "Xyz",
    "birthdate": "1996-11-01"
  }
];


var StateViewModel = function() {
  var self = this;
  self.students = ko.observableArray();

  setTimeout(function() {
    //console.log(sampleData)
    ko.mapping.fromJS(sampleData, {}, self.students);
  }, 1000);
}

var model = new StateViewModel();
ko.applyBindings(model);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<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>

<table>
  <tbody data-bind="foreach: students">
    <tr>
      <td> <input type="number" data-bind="value: index" name="index" readonly> </td>
      <td> <input type="text" data-bind="value: name" name="name" required> </td>
      <td> <input type="text" data-bind="value: surname" name="surname" required> </td>
      <td> <input type="date" data-bind="value: birthdate" name="birthdate" min="1950-01-01" max="2050-01-01" required> </td>
      <td><button type="button">Edit</button></td>
    </tr>
  </tbody>
</table>
Jason Spake
  • 4,293
  • 2
  • 14
  • 22
0

I also managed to solve my problem in this way:

'use strict';

var URL = 'http://localhost:8000/'

$(document).ready(function(){
    console.log("Abc")
    ko.applyBindings(new customerViewModel());
});

function customerViewModel() {
    var self = this;
    self.studentsList = ko.observableArray();

    $.ajax({
        type: 'GET',
        url: URL + 'students',
        contentType: "application/json",
        dataType: "json",
    success: function(data) {
        console.log(data)
        var observableData = ko.mapping.fromJS(data);
        var array = observableData();
        self.studentsList(array);
     },
    error:function(jq, st, error){
        alert(error);
    }
});
}

And using foreach

data-bind="foreach: studentsList"
Kate
  • 3
  • 1
  • 3