Aurasphere
Aurasphere

Reputation: 4011

KnockoutJS: foreach binding array inside observable

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!

Upvotes: 3

Views: 1704

Answers (1)

adiga
adiga

Reputation: 35202

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

Upvotes: 1

Related Questions