创建一个observable,它总结了动态创建的挖空视图模型中的每个属性

时间:2017-09-12 19:59:29

标签: knockout.js

我正在开发一个编辑器,它根据用户在我们应用程序的管理界面中定义的模板创建动态视图模型。动态意味着如果有100个可用数据点,用户可以选择在其模板中仅包含50个数据点及其相关提示。提示在UI中显示,如“患者年龄:”。我将此模板下拉到客户端并生成仅包含所选属性的挖空视图模型。编辑器的最终目标是收集所有必需的值,然后在摘要窗口中显示它们。当我最初开始思考这个时,我想我会创建一个computedObservable来保存摘要,然后(挥手)动态模型中的所有属性都可以在该observable中进行汇总。我很好,直到我尝试在预览窗口中实时更新的单个字符串中汇总所有属性值和提示。有人做过这样的事吗?

我知道我可以采取直接的方法,只是在calculateObservable中包含每个可能的属性,并在尝试提取值之前测试属性的存在,但我不得不相信有更好的方法我不在想的。

我没有包含任何代码,因为我正在寻找更多关于方法的指导而不是工作示例。

编辑:添加一个简化的例子来缩小我所要求的范围。我知道到目前为止给出的答案都是偏离基础的,因为我无法明确询问我在寻找什么。

我的应用程序将根据我从服务器下载的json对象的内容动态创建一个淘汰视图模型。因为我不知道这个对象在设计时会是什么样子,所以我不能在我的javascript代码中创建可观察的“Summary”,它也必须动态创建。

这是一个简化的例子:

假设我有一个使用来自此JSON对象的ko.mapping映射的淘汰视图模型(为简洁而减少):

{  
   "InitialGraphical":{  
      "GraphicalNoteId":0,
      "GraphicalNoteTemplateId":0,
      "NoteType":0,
      "InitialGraphical":{  
         "InitialGraphicalId":0,
         "InitialGraphicalEligibilityVerificationId":0,
         "ContinueReviewPer":null,
         "BirthSummary":null,
         "MaternalAge":null,
         "Gravida":null,
         "Para":null,
         "BirthWeight":null,
         "GestationalAge":null,
         "Delivery":null,
         "Apgar1Minute":null,
         "Apgar5Minute":null,
         "Apgar10Minute":null,
         "IPPlanOfCareSummary":null
      },
      "DailyDetails":{  
         "DailyDetailsId":0,
         "DateStart":"/Date(-62135578800000)/",
         "DateEnd":"/Date(-62135578800000)/",
         "Grams":0,
         "BedTypeId":0,
         "AdditionalBedTypeInfo":null,
         "VPShuntResivoirPatent":false,
         "Functional":false,
         "NASScore":0,
         "ScoreRange":null,
         "ScoreDate":"/Date(-62135578800000)/",
         "SeizureActivity":null,
         "HeadCircumference":0,
         "Rewarming":false
      }
   }
}

我想动态创建一个计算的observable,它包含视图模型中的每个属性并实时更新。我要创建的此属性绑定到一个文本区域,该区域将显示输入到视图模型中的所有值的摘要。所以,在伪代码中,我想这样做:

var Summary = ko.computed(function(){
    // iterate through all properties ViewModel and concatenate their values into 
    // a single string, then return that as the value of this computed
    // that updates when each property does.  <--- THIS IS THE QUESTION, HERE
});

1 个答案:

答案 0 :(得分:0)

您可以使用ko.toJSON在ViewModel中获取计算和可观察的JSON字符串(或ko.toJS以获取具有值的对象)。

&#13;
&#13;
var Model = function(){
  var self= this;
  self.test = ko.observable('test');
  
  self.test2 = ko.computed(function() {
    return self.test() + "2";
  });
};

var vm = new Model();
ko.applyBindings(vm);

setInterval(function() {
  console.log(ko.toJSON(vm));
},1000);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div>
  <input type="text" data-bind="textInput: test"/> 
  <span data-bind="text: test"></span>
</div>
Test2: 
<span data-bind="text: test2"></span>
&#13;
&#13;
&#13;

但是,尝试在VM中添加一个返回ko.toJSON的计算值意味着下次计算ko.toJSON(self)时,self.summary也将被考虑在其中。因此,随着时间的推移,摘要变量会因此而不断膨胀。这是一个如何(不)工作的例子:

&#13;
&#13;
var Model = function(){
  var self= this;
  self.test = ko.observable('test');
  
  self.test2 = ko.computed(function() {
    return self.test() + "2";
  });
  
  self.summary = ko.computed(function() {
    return ko.toJSON(self);
  });
};

var vm = new Model();
ko.applyBindings(vm);

setInterval(function() {
  console.log(vm.summary());
},1000);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div>
  <input type="text" data-bind="textInput: test"/> 
  <span data-bind="text: test"></span>
</div>
Test2: 
<span data-bind="text: test2"></span>
&#13;
&#13;
&#13;

如果必须将摘要作为计算结果,则可以在返回对象之前使用ko.toJS并删除summary属性。

&#13;
&#13;
var Model = function(){
  var self= this;
  self.test = ko.observable('test');
  
  self.test2 = ko.computed(function() {
    return self.test() + "2";
  });
  
  self.summary = ko.computed(function() {
    var obj = ko.toJS(self);
    delete obj.summary;
    return obj;
  });
};

var vm = new Model();
ko.applyBindings(vm);

setInterval(function() {
  console.log(vm.summary());
},1000);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div>
  <input type="text" data-bind="textInput: test"/> 
  <span data-bind="text: test"></span>
</div>
Test2: 
<span data-bind="text: test2"></span>
&#13;
&#13;
&#13;