【问题标题】:Nested foreach won't work嵌套的 foreach 不起作用
【发布时间】:2018-01-21 15:20:13
【问题描述】:

我无法让嵌套的 foreach 工作。我有以下代码:

HTML - 片段

<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 - 代码段

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);
}

基本上我想要完成的是在单选按钮中生成每个选择,并使数组中的 ID 成为单选按钮和标签的 ID。我已经成功地展示了它自己的选择。但是当我添加 data-bind='foreach: id'data-bind='attr: { id: $data }' 时,事情就停止了。我不断收到以下错误:

ReferenceError: Unable to process binding "foreach: function (){return id }" 消息:id 未定义

免责声明:我已经测试了数据,数组的一切都很好。

【问题讨论】:

  • 我认为问题在于您正在创建两个并非真正嵌套的数组。 idchoice 对象的属性。尝试删除段落标签&lt;p data-bind='foreach: id'&gt;,看看是否有效。
  • @styfle 单选按钮 id 与您上述解决方案的选择相同,这不是我想要的。 id 不是选择对象的属性。我要找的是这个。我有选择数组('Water'、'Air'、'Land、'Sea')和 id 数组('1'、'2'、'3'、'4')。单选按钮应该是“水”,ID 为“1”,下一个单选按钮应该是“空气”,ID 为“2”,依此类推。
  • 您想要 4 个输入:water:1, air:2, land:3, sea:4?或者您想要 16 个输入:water:1, air:1, land:1, sea:1, water:2, air:2, land:2, sea:2...
  • @styfle 第一个。
  • 可以添加原始 JSON 数据吗?

标签: javascript html knockout.js


【解决方案1】:

很抱歉没有使用您的代码布局,我找不到在哪里声明了问题或在哪里应用了绑定。我在这里使用一个简单的 3 项数据模型 QuestionModel 和一个包含它的简单视图模型做了一个示例。

数据模型仅包含问题的 ID、问题本身 (title) 以及该问题的选项。遍历每个问题,然后是每个选项。您可以根据需要扩展值的选择或任何其他内容。只需创建一个对象数组即可。

[{ 
  "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>

【讨论】:

    【解决方案2】:

    由于id 不是choice 的一部分,您需要使用$parent 来引用它:

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

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

    【讨论】:

      【解决方案3】:

      您应该在模型中添加一组看起来像{id: 1} 的选项。然后您可以循环选择并引用id 属性,如下所示:

      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>

      【讨论】:

      • 我认为您误解了我正在解释的所有内容或误解了代码。代码中已经有一个 ID 数组。我只需要将它们添加为单选按钮的 ID。您的上述解决方案没有提供任何方法让选择本身显示为单选按钮的标签。注意到我在 questionModel 中有一个 id 数组。