0

Using Knockout, I am trying to compute a nested array value and display it in the front-end. Please find my code below

View Model Code:

var viewModel = function  () {
var self = this;
self.profile = ko.observableArray ([{
  personal: [
    {firstName: 'Captain', lastName: 'Flint'},
    {firstName: 'Jhon', lastName: 'Silver'},
    {firstName: 'Jack', lastName: 'Rackham'}
  ]
}]);
self.fullName = ko.computed (function () {
  for (var i=0; i<self.profile()[0].personal.length; i++) {
    self.profile()[0].personal[i].firstName+" "+ self.profile()[0].personal[i].lastName;
  });
}
ko.applyBindings(new viewModel);

HTML

<table data-bind="foreach: profile">
  <tbody data-bind="foreach: personal">
    <tr>
      <td data-bind="text: $index"></td>
      <td data-bind="text: fullname"></td>
    </tr>
  </tbody>
</table>

Yes! this does not work. Tried Knockout documentation and many other tutorials unable find the best solution. Kindly help me with this issue. Thanks in advance.

1 Answers1

1

Your binding hierarchy has 3 levels:

  • Root
    • Profile
      • Personal

In order to access the fullname property from within the bottom level (inside foreach:personal) it has to reside on the "personal" object. In other words there must be a separate computed property defined for every single object in the array. You can loop through them and add the properties in your view-model construction like this:

var viewModel = function () {
  var self = this;
  self.profile = ko.observableArray([
    { personal: [
        {firstName: 'Captain', lastName: 'Flint'},
        {firstName: 'Jhon', lastName: 'Silver'},
        {firstName: 'Jack', lastName: 'Rackham'}
    ]}
  ]);
  
  for(var i=0; i<self.profile().length; i++){
    var profile = self.profile()[i];
    for(var j=0; j<profile.personal.length; j++){
      var personal = profile.personal[j];
      personal.fullname = ko.computed(function(){
        return this.firstName + " " + this.lastName;
      }, personal);
    }
  }
  
}

ko.applyBindings(new viewModel());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<table data-bind="foreach: profile">
  <tbody data-bind="foreach: personal">
    <tr>
      <td data-bind="text: $index"></td>
      <td data-bind="text: fullname"></td>
    </tr>
  </tbody>
</table>

That being said, you can make the code more readable and manageable by making classes for "profile" and "personal", and then the computed property could just reside on the personal class.

Michael Best
  • 16,623
  • 1
  • 37
  • 70
Jason Spake
  • 4,293
  • 2
  • 14
  • 22