Data binding Checkboxes using Knockout Observable Arrays

285 Views Asked by At

I'm trying to reimplement a student attendance example from the Udacity JavaScript Design Patterns course. So far I've managed to recreate the table and correctly populate it with some student data, however it appears when I change a checkbox value this isn't updated in the model.

For example, when I display

    debugVM.studentList()[0].days();

in the console the output displays the initial attendance data instead of the current state of the checkboxes. A JSFiddle for this can be found here.

index.html

 <table>
  <thead>
    <tr>
      <th>Student</th>
      <!-- ko foreach: attendance -->
      <th data-bind="html: $data"></th>
      <!-- /ko -->
    </tr>
  </thead>
  <tbody data-bind="foreach: studentList">
    <tr>
      <td data-bind="html: name, click: $parent.debugStudent"></td>
      <!-- ko foreach: days -->
      <td>
      <input type="checkbox" data-bind="value: $data, checkedValue: $data, checked: $data" />
      </td>
      <!-- /ko -->
    </tr>
  </tbody>
</table>

app.js

var Student = function(student){

  this.name = ko.observable(student.name);
  this.days = ko.observableArray(student.days);
};


var ViewModel = function() {
  var self = this;

  this.attendance = ko.observableArray([1,2,3,4,5,6,7,8,9,10,11,12]);
  this.studentList = ko.observableArray([]);

  students.forEach(function(student) {
    self.studentList.push(new Student(student));
  });

  self.debugStudent = function() {
    console.log(self.studentList()[0].days());
  };
};
var debugVM = new ViewModel();

ko.applyBindings(debugVM);
1

There are 1 best solutions below

0
Max Brodin On BEST ANSWER

From the knockout documentation

Key point: An observableArray tracks which objects are in the array, not the state of those objects

In your case this means that days should be not observable array, but array of observables.

For example you can add new viewModel Day:

var Day = function(isChecked) {
    this.isChecked = ko.observable(isChecked);
}

And set the days property like this

this.days = [];
for (var i = 0; i< student.days.length; i++) {
   this.days.push(new Day(student.days[i] == 1));
}

See working fiddle