Reputation: 47
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
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
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
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