DanielleS
DanielleS

Reputation: 47

Nested foreach won't work

I cannot get a nested foreach to work. I have the following code:

HTML - Snippet

<div data-bind='foreach: choice'>
    <p data-bind='foreach: id'>
        <input name="group1" type="radio" data-bind="attr: { id: $data }"/> <label  data-bind="attr: { for: $data} "> <span data-bind=" text: $data"> </span>
        </label>
    </p>
</div>

Javascript - Snippet

var questionModel = { 
question : ko.observable(), 
id: ko.observableArray(), 
choice: ko.observableArray() 
}

function startTest() {
    questionModel.question(questions[questionNo].question);
    var m = [];
    var i = [];

    var e = 0;
    while (e != 4) {
        m.push(choices[questionNo][e].choice);
        i.push(choices[questionNo][e].id);
        e++;
    }

    questionModel.choice(m);
    questionModel.id(i);
}

Essentially what I'm trying to accomplish is for each choice to be generated within a radio button and to have the IDs within the array be the id for the radio button and label. I've successfully displayed the choices on it's own. But when I added the data-bind='foreach: id' & data-bind='attr: { id: $data }', that's when things stopped working. I keep getting the error below:

ReferenceError: Unable to process binding "foreach: function (){return id }" Message: id is not defined

Disclaimer: I've tested the data and everything for the arrays are fine.

Upvotes: 0

Views: 397

Answers (3)

Michael Best
Michael Best

Reputation: 16688

Since id is not part of choice, you need to use $parent to reference it:

data-bind="foreach: $parent.id"

https://jsfiddle.net/mbest/08gk7h4v/

Upvotes: 1

John Pavek
John Pavek

Reputation: 2665

I'm sorry for not using your code layout, I couldn't find where questions was declared or where the bindings were applied. I made an example here using a simple 3 item data model, QuestionModel, and a simple view model containing it.

The data model just contains the ID for the question, the question itself (title) and then the choices for that question. Loop through each question, and then each of the choices. You can expand on the choices for values or whatever if you'd like. Just make an array of objects.

[{ 
  "AnswerText": "Blue", 
  "AnswerValue" : "#0000FF"
}]

function QuestionModel(data) {
  var self = this;

  self.Id = ko.observable(data.Id);
  self.Title = ko.observable(data.Title);
  self.Choices = ko.observableArray(data.Choices);

}

function ViewModel() {
  var self = this;

  self.Questions = ko.observableArray([
    new QuestionModel({
      "Id": 1,
      "Title": "What color are rabbits?",
      "Choices": ["Red", "Blue", "Green"]
    }),
    new QuestionModel({
      "Id": 2,
      "Title": "What color are dogs?",
      "Choices": ["Silver ", "Golden", "Striped"]
    }),
    new QuestionModel({
      "Id": 3,
      "Title": "What color are cats?",
      "Choices": ["white", "Black", "Orange"]
    })
  ]);

}
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="foreach: Questions">
  <span data-bind="text: Title"> </span>
  <div data-bind="foreach: Choices">
    <input type="radio" data-bind="value: $data, attr : {name : $parent.Id}" />
    <span data-bind="text: $data"></span>
    <br>
  </div>
</div>

Upvotes: 2

styfle
styfle

Reputation: 24610

You should add an array of choices that look like {id: 1} to the model. Then you can loop over the choices and reference the id property like so:

var questionModel = {
  question: ko.observable(),
  choice: ko.observableArray()
}

function startTest() {
  questionModel.question(questions[questionNo].question);
  var m = [];
  var e = 0;
  while (e != 4) {
    var choice = choices[questionNo][e];
    m.push(choice);
    e++;
  }

  questionModel.choice(m);
}
<div data-bind="foreach: choice">
  <p>
    <input name="group1" type="radio" data-bind="attr: { id: id }" />
    <label data-bind="attr: { for: id }">
        <span data-bind="text: id"> </span>
        </label>
  </p>
</div>

Upvotes: 0

Related Questions