循环访问 Knockout - 绑定错误中的不同对象的数组

Looping over an array of different objects in Knockout - Binding Error

本文关键字:对象 数组 错误 访问 Knockout 绑定 循环      更新时间:2023-09-26

我正在尝试呈现页面的不同部分,并为单个数组中包含的不同项目应用适当的绑定。数组中的每个项目都可以具有不同的结构/属性。

例如,我们可以有 3 种不同的问题类型,与该问题关联的数据可以采用不同的格式。

数据

var QuestionTypes = { Textbox: 0, Checkbox: 1, Something: 2 }
var QuestionData = [
    {
        Title: "Textbox",
        Type: QuestionTypes.Textbox,
        Value: "A"
    },
    {
        Title: "Checkbox",
        Type: QuestionTypes.Checkbox,
        Checked: "true"
    },
    {
        Title: "Custom",
        Type: QuestionTypes.Something,
        Something: { SubTitle : "Something...", Description : "...." }
    }
];

JavaScript

$(document).ready(function(){
    ko.applyBindings(new Model(QuestionData), $("#container")[0]);
})
function QuestionModel(data){
    var self = this;
  self.title = ko.observable(data.Title);  
  self.type = ko.observable(data.Type);
  self.isTextbox = ko.computed(function(){
    return self.type() === QuestionTypes.Textbox;
  });
  self.isCheckbox = ko.computed(function(){
    return self.type() === QuestionTypes.Checkbox;
  });
  self.isSomething = ko.computed(function(){
    return self.type() === QuestionTypes.Something;
  });
}
function Model(data){
    var self = this;
  self.questionData = ko.observableArray(ko.utils.arrayMap(data, function(question){
    return new QuestionModel(question); 
  }));  
}

.HTML

<div id="container">  
  <div data-bind="foreach: questionData">
    <h1 data-bind="text: title"></h1>
    <!-- ko:if isTextbox() -->
    <div data-bind="text: Value"></div>
    <!-- /ko -->
    <!-- ko:if isCheckbox() -->
    <div data-bind="text: Checked"></div>
    <!-- /ko -->
    <!-- ko:if isSomething() -->
    <div data-bind="text: Something">
      <h1 data-text: SubTitle></h1>
      <div data-text: Description></div>
    </div>
    <!-- /ko -->
  </div>
</div>

如果条件为真/假,则应用 if 条件中的绑定。这会导致 JavaScript 错误...因为并非集合中的所有对象都具有"Value"属性等。

Uncaught ReferenceError: Unable to process binding "foreach: function (){return questionData }"
Message: Unable to process binding "text: function (){return Value }"
Message: Value is not defined

有没有办法防止绑定应用于错误的对象?

概念 JSFiddle: https://jsfiddle.net/n2fucrwh/

请在不更改代码的情况下查看更新的小提琴手。仅在循环侧添加$data

https://jsfiddle.net/n2fucrwh/3/

 <!-- ko:if isTextbox() -->
<div data-bind="text: $data.Value"></div>
<!-- /ko -->
<!-- ko:if isCheckbox() -->
<div data-bind="text: $data.Checked"></div>
<!-- /ko -->
<!-- ko:if isSomething() -->
<div data-bind="text: $data.Something"></div>
<!-- /ko -->

在循环中,您需要提供 $data.Value.It 似乎 值是与绑定冲突的淘汰赛的关键词。

首先,您的"问题模型"没有相应的属性:您仅从传入数据中创建"类型"和"标题"字段。

建议的解决方案:

您可以对不同的数据类型使用不同的模板。我已经更新了你的小提琴:

var QuestionTypes = { Textbox: 0, Checkbox: 1, Something: 2 }
var QuestionData = [
    {
        Title: "Textbox",
        Type: QuestionTypes.Textbox,
        templateName: "template1",
        Value: "A"
        
    },
    {
        Title: "Checkbox",
        Type: QuestionTypes.Checkbox,
        templateName: "template2",
        Checked: "true"
    },
    {
        Title: "Custom",
        Type: QuestionTypes.Something,
        templateName: "template3",
        Something: "Something"
    }
];
$(document).ready(function(){
	ko.applyBindings(new Model(QuestionData), $("#container")[0]);
})
function QuestionModel(data){
	var self = this;
  
  self.title = ko.observable(data.Title);  
  self.type = ko.observable(data.Type);
  self.data = data;
}
function Model(data){
	var self = this;
	
  self.questionData = ko.observableArray(ko.utils.arrayMap(data, function(question){
  	return new QuestionModel(question);	
  }));  
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script type="text/html" id="template1">
    <div data-bind="text: Value"></div>
</script>
<script type="text/html" id="template2">
    <div data-bind="text: Checked"></div>
</script>
<script type="text/html" id="template3">
    <div data-bind="text: Something"></div>
</script>
<div id="container">  
  <div data-bind="foreach: questionData">
    <h1 data-bind="text: title"></h1>
    <!-- ko with: data -->
      <!-- ko template: templateName -->
      <!-- /ko -->
    <!-- /ko -->
  </div>
</div>

在上面的版本中,您可以摆脱"问题类型"。

更新 1

当然,您可以从问题类型中计算模板名称。

更新 2

错误原因的说明。如果检查原始视图模型:

function QuestionModel(data){
    var self = this;
  self.title = ko.observable(data.Title);  
  self.type = ko.observable(data.Type);
  self.isTextbox = ko.computed(function(){
    return self.type() === QuestionTypes.Textbox;
  });
  self.isCheckbox = ko.computed(function(){
    return self.type() === QuestionTypes.Checkbox;
  });
  self.isSomething = ko.computed(function(){
    return self.type() === QuestionTypes.Something;
  });
}

您可以看到,"QuestionModel"具有以下属性:"title","type","isTextbox","isCheckbox"和"isSomething"。

因此,如果您尝试将模板绑定到"值","已检查"或"某些内容",则会收到错误,因为视图模型不包含此类属性。

将绑定语法更改为

<div data-bind="text: $data.Value"></div>

或类似的东西可以消除错误,但在这种情况下始终不会显示任何内容。