访问viewmodel Knockout中的对象

时间:2014-06-11 15:07:44

标签: javascript mvvm knockout.js

我使用knockout为单页应用程序,它根据几个输入执行一些基本计算,然后填充某些html的值。为了保持我的html简洁,我在viewModel中使用了一组对象来存储我的表单。我实现了页面的基本功能,但是我希望添加一个' display'在html上显示的值,该格式已经格式化了小数点,并且可能是未来的转换值。

我不确定最佳做法'访问我目前在'中的对象的其他值的方式。例如:如果我希望我的显示字段是一个计算值,该值包含四舍五入到小数点后两位的值字段。

display: ko.computed(function()
{
  return Math.round(100 * myObj.value())/100;
}

我一直在阅读淘汰赛的文档,看来管理这个是图书馆新手的常见问题。我相信我可以通过在viewmodel原型之外添加计算函数并通过

访问对象来使其工作
viewModel.input[1].value()

但是,我认为有一种更清洁的方法来实现这一目标。

我已经提供了一个viewModel的小片段供参考。输入数组总共包含15个元素。 HTML包含在下面。

var ViewModel = function()
{
  var self = this;
  this.unitType = ko.observable('imperial');
  this.input = 
  [
    {
      name: "Test Stand Configuration",
      isInput: false
    },
    {
      name: "Charge Pump Displacement",
      disabled: false,
      isInput: true,
      unitImperial: "cubic inches/rev",
      unitMetric: "cm^3/rev",
      convert: function(incomingSystem)
      {
        var newValue = this.value();
        if(incomingSystem == 'metric')
        {
          //switch to metric
          newValue = convert.cubicinchesToCubiccentimeters(newValue);   
        }
        else
        {
          //switch to imperial
          newValue = convert.cubiccentimetersToCubicinches(newValue);
        }
        this.value(newValue);
      },
      value: ko.observable(1.4),
      display: ko.computed(function()
      {
        console.log(self);
      }, self)
    }
  ]
};

__

<!-- ko foreach: input -->
    <!-- ko if: $data.isInput == true -->
    <div class="form-group">
            <div class="col-sm-6">
                    <label class="control-label" data-bind="text: $data.name"></label>
            </div>
            <div class="col-sm-6">
                <div class="input-group">
                <!-- ko if: $data.disabled == true -->
                    <input data-bind="value: $data.value" type="text" class="form-control" disabled>
                <!-- /ko -->
                <!-- ko if: $data.disabled == false -->
            <input data-bind="value: $data.value" type="text" class="form-control">
                <!-- /ko -->
                <!-- ko if: viewModel.unitType() == 'imperial'-->
            <span data-bind="text: $data.unitImperial" class="input-group-addon"></span>
                <!-- /ko -->
                <!-- ko if: viewModel.unitType() == 'metric' -->
            <span data-bind="text: $data.unitMetric" class="input-group-addon"></span>
                <!-- /ko -->
                </div>
            </div>
    </div>
<!-- /ko -->
<!-- ko if: $data.isInput == false -->
<div class="form-group">
    <div class="col-sm-6">
            <h3 data-bind="text: $data.name"></h3>
    </div>
</div>
<!-- /ko -->

2 个答案:

答案 0 :(得分:2)

如果你想读/写&amp;从同样的输出,@ Aaron Siciliano的答案是要走的路。否则,......

  

我不确定访问&gt;对象的其他值的“最佳实践”方式我现在'进去'。例如:如果我希望我的显示字段是一个计算值,该值包含四舍五入到小数点后两位的值字段。

我认为这里有一个关于KnockoutJS的误解。 KnockoutJS允许您在Javascript中处理所有逻辑。通过Knockout的上下文变量访问您所在对象的值很简单:$data(当前上下文,与JS的this相同),$parent(父上下文), $root(根视图模型上下文)以及Binding Context处的更多内容。您可以在模板和Javascript中使用此变量。顺便说一下,$index返回数组项的 observable 索引(这意味着当你做某事时它会自动改变。)。在你的例子中,它就像:

一样简单
<span data-bind="$data.display"></span>

或者假设你想从你的根,甚至父母那里得到一个可观察的w / e。 (场景:购买的每件商品都会增加的成本指标,它们分别存储在一个数组中)。

<span data-bind="$root.totalValue"></span>

如果我错了,请纠正我,但鉴于您仅在视图模型中定义了self,显示功能应将整个根视图模型输出到控制台。如果在数组中重新定义对象内的self变量,self将在数组中输出该对象。这取决于变量的范围。你不能使用对象文字,你需要一个构造函数(就像你的视图模型一样)。所以你得到:

function viewModel() {
  var self = this;
  self.inputs = ko.observableArray([
    // this builds a new instance of the 'input' prototype
    new Input({initial: 0, name: 'someinput', display: someFunction}); 
  ])
}
// a constructor for your 15 inputs, which takes an object as parameter
function Input(obj) { 
  var self = this; // now self refers to a single instance of the 'input' prototype
  self.initial = ko.observable(obj.initial); //blank
  self.name = obj.name;
  self.display = ko.computed(obj.fn, this); // your function
}

正如您所提到的,您之后也可以处理事件,请参阅:unobtrusive event handling。使用ko.dataFor&amp;添加您的事件监听器ko.contextFor方法。

答案 1 :(得分:0)

似乎KnockoutJS在其网站上为这个确切的场景设置了一个示例。

http://knockoutjs.com/documentation/extenders.html

从阅读该页面看起来好像你可以创建一个扩展器来拦截一个observable,然后再更新并向它应用一个函数(将其格式化为货币或圆形或执行在更新之前需要对其进行的任何更改ui)。

这可能是你想要的最接近的东西。但是,对你完全诚实,我喜欢你解决这个问题的简单方法。