3

This is my data model (a survey):

{ 
 "name" : "x",
 "questions" : [ .... ]
}

This is my viewModel:

survey : ko.observable(undefined)

This is my data-bind tag:

<ol data-bind="foreach: data.survey.questions">

It doesn't work. It works if I change the binding like this:

<ol data-bind="foreach: data.survey().questions">

The problem is that inside the foreach binding there's another foreach looping through the possible answers to the questions:

<div data-bind="foreach: answers">

I didn't find any way to make this one work with my current setup. Basically I think the problem is that you need to use an observableArray but I want to loop on an array inside an observable instead.

Can anyone suggest a way to make this double foreach work? Thanks!

Aurasphere
  • 3,841
  • 12
  • 44
  • 71

1 Answers1

1

Knockout observables are functions. To read the observable’s value, you need to call the observable with no parameters. Hence you need the survey() to access the inner object which has questions property.


I'm not sure why your inner foreach binding isn't working. I would guess it's because you are setting survey to undefined. But since the outer foreach is working it couldn't be that. And you mentioned, "I think the problem is that you need to use an observableArray". That's not necessary. Knockout's default binding handlers, including the foreach binding, internally handle this by using ko.utils.unwrapObservable(). The only difference being, if it's an observableArray, any changes to the array in the future will be reflected on the UI. But if it's a regular array, then the UI won't be updated.

So, if there is an array called answers within each question, then it should work. Here's a working snippet.

var data = {
  survey: ko.observable({
    "name": "x",
    "questions": [{
      text: "Who let the dogs out?",
      answers: [
       {number: 1,text: "Cats"}, 
       {number: 2,text: "Baha Men"}
      ]
    }, {
      text: "What does the fox say?",
      answers: [
       {number: 1,text: "Woof Woof"}, 
       {number: 2,text: "Ring-ding-ding-dingeringeding"}, 
       {number: 3,text: "Meow Meow"}
      ]
    }]
  })
};

ko.applyBindings(data)
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js"></script>
<ol data-bind="foreach: survey().questions">
  <li>
    <span data-bind="text: text"></span>
    <br> Answers:

    <ul data-bind="foreach: answers">
      <li data-bind="text:text">
      </li>
    </ul>
  </li>
</ol>

Here's a fiddle for testing

adiga
  • 34,372
  • 9
  • 61
  • 83
  • Thanks for the help. My code is exactly like yours. The only difference is the applyBinding. Since I'm working on a RIA and I switch dinamically the page content I use this snippet: ko.applyBindings({"data" : data}, $(".page-content")[0]); Also, the strange thing is that I get no error and this works flawlessly in the nested elements of the object (like the text question) but not on the nested foreach... – Aurasphere Oct 22 '17 at 10:12
  • 1
    @Aurasphere that's strange. I have created [a fiddle](https://jsfiddle.net/adigas/oewydd14/4/) to mimic your structure. Make sure you have nested the array and the html properly. – adiga Oct 22 '17 at 10:24
  • I've solved the problem! It seems it was caused by a nested binding that was undefined preventing the parent to bind somehow... What I did to fix it was just adding a reference to the parent ($data) before the undefined binding. That let KO initialize the value itself, even if it's still not clear to me why I didn't get any error in console and why this isn't the default behaviour (I'm a JS newbie though). This was the answer that saved me: https://stackoverflow.com/a/9281765/4921205 I wouldn't be able to solve this issue without your help in debugging! Many thanks! – Aurasphere Oct 22 '17 at 11:03