【问题标题】:Looping over an array of different objects in Knockout - Binding Error在 Knockout 中循环遍历不同对象的数组 - 绑定错误
【发布时间】:2016-01-24 22:41:33
【问题描述】:

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

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

JSON 数据

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 错误...因为并非集合中的所有对象都具有“值”属性等。

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/

【问题讨论】:

    标签: javascript knockout.js


    【解决方案1】:

    请在不更改代码的情况下查看更新的 Fiddler。仅在循环中添加 $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。看来Value是淘汰赛中的关键字与绑定冲突。

    【讨论】:

    • 我通常会做!!$data.Value,但是很好的解决OP问题
    • IMO,这不是最佳选择。这看起来像“程序代码”,但@TSV 的答案看起来更像是“声明性代码”,这是我希望在 KO 视图中找到的。 OTOH,另一个答案可以通过使用组件来扩展,不仅允许更改视图,还允许使用类似技术的脚本(用于视图模型的 JavaScript)
    【解决方案2】:

    首先,您的“QuestionModel”没有相应的属性:您只能从传入数据创建“类型”和“标题”字段。

    建议的解决方案:

    您可以为不同的数据类型使用不同的模板。 我更新了你的fiddle

    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>

    在上面的版本中你可以去掉“QuestionTypes”。

    更新 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”。

    因此,如果您尝试将模板绑定到“Value”、“Checked”或“Something”,您将收到错误消息,因为视图模型不包含此类属性。

    将绑定语法更改为

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

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

    【讨论】:

    • 两个建议:1)我会给模板更重要的名字。为什么不称它们为“文本框”、“复选框”、“某物”? 2)如果您的问题具有不同的相关功能,您可以扩展这个想法并使用组件而不是模板。模板仅定义“视图”部分。但是组件也可以添加一些脚本。
    • @JotaBe 我明白并同意你的观点。我想到了我的名字。可以在生产代码中美化。
    猜你喜欢
    • 1970-01-01
    • 2019-12-11
    • 2016-09-07
    • 1970-01-01
    • 2019-09-12
    • 2021-09-06
    • 1970-01-01
    • 2016-07-28
    • 2017-01-29
    相关资源
    最近更新 更多