单选按钮绑定计算

时间:2015-11-03 10:51:51

标签: javascript knockout.js

我有一些关于knockoutjs可写的问题我认为可以计算可观察量 我创建了一个fiddle

我需要的实际上并不那么难:
我有可空的position="attributes"/"replace"WeightInGramms值 这些值应绑定到两个输入字段(其中只有一个应该可见) 在顶部,用户可以选择要使用单选按钮的这些值中的哪一个。

在初始化时,当它们都为空时," g"当VolumeInMilliliters不为空时,也应检查单选按钮。当WeightInGramms有一些价值时," ml"应检查单选按钮。

我为此使用了 knockoutjs writable计算可观察,如果有更好的方法,请纠正我!

因此,当我更改输入中绑定到VolumeInMillilitersWeightInGramms的值时,read函数似乎有效。但是,当我改变单选按钮时,没有任何事情发生......

VolumeInMilliliters

当我更改单选按钮时,相应的输入字段应该是可见的:

var ViewModel = function (data) {
    var self = this;
    this.VolumeInMilliliters = ko.observable(data.VolumeInMilliliters);
    this.WeightInGramms = ko.observable(data.WeightInGramms);

    this.GrammIsSelected = ko.computed({
        read: function() {
            return (!self.WeightInGramms() && !self.VolumeInMilliliters()) || !self.VolumeInMilliliters();
    },
        write: function (newValue) {
            console.log(newValue);
            return newValue;
        },
        owner: this
    });

};

编辑:
当第一次加载表单时,两个值都将为null - > " g"应该检查按钮。

可以使用以下内容初始化observable:

<div data-bind="visible: GrammIsSelected">g is active</div>
<div data-bind="visible: !GrammIsSelected()">ml is active</div>

两者都可以为null,但只有一个可以有值。 如果用户键入一个值,然后单击另一个单选按钮,则该值可以应用于另一个值。

我跳得更清楚了

3 个答案:

答案 0 :(得分:2)

一些提示:

  • 尽可能使viewModel(JS)与视图(HTML)相似。此外,这可以避免重复过多的标记。在这种情况下,单选按钮始终是列表,因此最方便的是将选项存储在数组中。
  • 您应该定义一个包含所选指标的GrammIsselected observable,而不是测试是否selected。这样,如果您添加了更多选项,代码仍然可以在不重构的情况下运行。
  • 何时使用计算属性?计算属性通过基于多个observables / variables计算结果来添加 readonly 值。可写的计算属性也是如此,除非您可以回写更改。这使得它对“全选”样式复选框(请参阅example 2 in the docs),数据验证&amp;变换。

您希望实现的目标绝对最清晰:

var ViewModel = function (data) {
    this.metrics = [
        { name: 'g',  value: ko.observable(data.WeightInGramms) },
        { name: 'ml', value: ko.observable(data.VolumeInMilliliters) }
    ];
    this.selectedMetric = ko.observable(this.metrics[0]);
};

通过将对象设置为可观察对象(selectedMetric),您可以进一步简化音量/权重输入的标记:

<div class="control-group">
    <label class="control-label">choose</label>
    <div class="controls" data-bind="with: selectedMetric">
        <input type="text" data-bind="value: value">
        <span class="help-inline" data-bind="text: '(' + name + ')'"></span>
    </div>
</div>

获取应用的“最终价值”就像检索selectedMetric().value()一样简单。

计算属性在这里并不是非常有用,但是,例如,如果您想为用户提供一种方法来设置带有单选按钮和文本的g / ml,您可以将以下方法添加到viewModel:

this.selectedMetricByText = ko.computed({
    read: function() {
        return this.selectedMetric().name;
    },
    write: function(value) {
        var newMetric = ko.utils.arrayFirst(this.metrics, function(metric) {
            return metric.name === value;
        }) || false;
        this.selectedMetric(newMetric || this.metrics[0]);
    }
}, this);

Fiddle

答案 1 :(得分:1)

你的write函数似乎没有任何东西,似乎?

this other answer相反,根据我的经验,我会给你建议以避免可写计算:明智地使用它们会非常有效!

注意:在我的回答中,我尝试与问题中的原始设计保持接近,但如果您能够(有资源可用),我建议根据the answer by @Tyblitz重新设计更多内容。

以下是使用计算机来解决这个问题的方法:

var ViewModel = function (data) {
  var self = this;
  
  self.VolumeInMilliliters = ko.observable(data.VolumeInMilliliters);
  self.WeightInGramms = ko.observable(data.WeightInGramms);

  var _measurementType = ko.observable("volume");

  self.MeasurementType = ko.computed({
    read: function() {
      return _measurementType();
    },
    write: function (newValue) {
      _measurementType(newValue);
      self.VolumeInMilliliters(newValue === "volume" ? 0 : null);
      self.WeightInGramms(newValue === "mass" ? 0 : null);
    }
  });
};

ko.applyBindings(new ViewModel({ VolumeInMilliliters: 12 }));
label { cursor: pointer; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<label>
  <input type="radio" name="measurementType" value="volume" data-bind="checked: MeasurementType">
  Volume
</label>
<input data-bind="value: VolumeInMilliliters, enable: MeasurementType() === 'volume'">

<label>
  <input type="radio" name="measurementType" value="mass" data-bind="checked: MeasurementType">
  Weight in gramms
</label>
<input data-bind="value: WeightInGramms, enable: MeasurementType() === 'mass'">

答案 2 :(得分:0)

对于单选按钮,您需要使用&#34;已选中&#34;捆绑。

http://knockoutjs.com/documentation/checked-binding.html

根据我的个人经历(作为KO nija),我必须给你建议:避免可写的ko计算。

<input type="radio" name="unitSelector" value="g" data-bind="checked: unit" /> Grams</br>
<input type="radio" name="unitSelector" value="ml" data-bind="checked: unit" /> Millis</br>

现在是视图模型

var ViewModel = function (data) {
    var self = this;
    self.unit = ko.observable('g');
    self.userValue = ko.observable(data.WeightInGramms);
};

现在绑定应该只关心用户输入的值,你不需要在这里计算,你不需要两个字段......

<input type="text" data-bind="textInput: userValue ">
<span data-bind="text: unit">  </span>

它看起来真的太简单但是你需要的东西,正如@Jotabe所提到的,你应该把测量和单位作为两个单独的东西......你以后用这个东西做什么,可以用计算机完成可观测量。

如果这件事没有解决你的问题那么你应该说出你真正想要的东西......