Knockout.js 我如何为格式化数字的文本框创建一个剔除自定义绑定?

Knockout.js 我如何为格式化数字的文本框创建一个剔除自定义绑定?,knockout.js,Knockout.js,我有一个可观察的对象,绑定到input type=“text”HTML元素。可观察对象包含浮点数。我希望文本框中的值显示为小数点后2位。所以1是1.00,1.2是1.20,依此类推。我创建了一个自定义绑定,我认为它可以输出格式化值,但不能捕获用户输入: ko.bindingHandlers.numericValue = { init: function (element, valueAccessor, allBindingsAccessor, viewModel) { },

我有一个可观察的对象,绑定到
input type=“text”
HTML元素。可观察对象包含浮点数。我希望文本框中的值显示为小数点后2位。所以1是1.00,1.2是1.20,依此类推。我创建了一个自定义绑定,我认为它可以输出格式化值,但不能捕获用户输入:

ko.bindingHandlers.numericValue = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
    },
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor()),
            precision = ko.utils.unwrapObservable(allBindingsAccessor().precision) || ko.bindingHandlers.numericValue.defaultPrecision;

        var formattedValue = '';
        if (value) {
            if (typeof value === "string") {
                value = parseFloat(value);
            }
            formattedValue = value.toFixed(precision);
        } else {
            value = 0;
            formattedValue = value.toFixed(precision);
        }
        $(element).val(formattedValue);
    },
    defaultPrecision: 1
};
绑定:

可在模型上观察到:

    self.marketRate = ko.observable(formatNumber(dc.marketRate, 2)).extend({
        required: { message: 'Required', onlyIf: function() { return self.isSelected(); }},
        min: { params: 0, onlyIf: function () { return self.isSelected(); } },
        max: { params: 999999.99, onlyIf: function() { return self.isSelected(); } },
        pattern: { message: 'Maximum 2 decimal places', params: /^\d*(\.\d{1,2})?$/, onlyIf: function () { return self.isSelected(); } }
    });

function formatNumber(value, places) {
        value = ko.utils.unwrapObservable(value);
        if (value) {
            if (typeof value === "string") {
                value = parseFloat(value);
            }
            return value.toFixed(places);
        }
        value = 0;
        return value.toFixed(places);
    }

我需要用用户输入的值来更新可观测值吗?此代码从不更新可观察的对象。我的猜测是我需要调用敲除值绑定代码。

据我所知,有几个选项。您可以在init函数中设置一个事件绑定,该绑定将在值更改时直接处理可观察对象的更新。看起来像这样

init: function (element, valueAccessor, allBindings) {
    var valueObservable = valueAccessor();

    ko.utils.registerEventHandler(element, "change", function () {
      valueObservable($(element).val());
    });
}
另一个选项是通过将format函数转换为可写的computed,然后在init绑定中使用以下命令将“value”绑定分配给该computed,从而利用现有的值绑定。在这种情况下,不需要更新函数

ko.applyBindingAccessorsToNode(element, { value: formattingComputed }, bindingContext);
在您的特定示例中,可能如下所示:

ko.bindingHandlers.numericValue = {
  init: function (element, valueAccessor, allBindingsAccessor, data, bindingContext) {
    var formattingComputed = ko.computed({
        read: function(){
          var value = ko.utils.unwrapObservable(valueAccessor()),
              precision = ko.utils.unwrapObservable(allBindingsAccessor().precision) || ko.bindingHandlers.numericValue.defaultPrecision;

          var formattedValue = '';
          if (value) {
              if (typeof value === "string") {
                  value = parseFloat(value);
              }
              formattedValue = value.toFixed(precision);
          } else {
              value = 0;
              formattedValue = value.toFixed(precision);
          }
          formattedValue = value.toFixed(precision);
          return formattedValue;
        },
        write: function(value){
            ko.expressionRewriting.writeValueToProperty(valueAccessor(), allBindingsAccessor, 'value', value);
        }
    });
    ko.applyBindingAccessorsToNode(element, { value: function(){return formattingComputed;} }, bindingContext);
  }
}

据我所知,有两种选择。您可以在init函数中设置一个事件绑定,该绑定将在值更改时直接处理可观察对象的更新。看起来像这样

init: function (element, valueAccessor, allBindings) {
    var valueObservable = valueAccessor();

    ko.utils.registerEventHandler(element, "change", function () {
      valueObservable($(element).val());
    });
}
另一个选项是通过将format函数转换为可写的computed,然后在init绑定中使用以下命令将“value”绑定分配给该computed,从而利用现有的值绑定。在这种情况下,不需要更新函数

ko.applyBindingAccessorsToNode(element, { value: formattingComputed }, bindingContext);
在您的特定示例中,可能如下所示:

ko.bindingHandlers.numericValue = {
  init: function (element, valueAccessor, allBindingsAccessor, data, bindingContext) {
    var formattingComputed = ko.computed({
        read: function(){
          var value = ko.utils.unwrapObservable(valueAccessor()),
              precision = ko.utils.unwrapObservable(allBindingsAccessor().precision) || ko.bindingHandlers.numericValue.defaultPrecision;

          var formattedValue = '';
          if (value) {
              if (typeof value === "string") {
                  value = parseFloat(value);
              }
              formattedValue = value.toFixed(precision);
          } else {
              value = 0;
              formattedValue = value.toFixed(precision);
          }
          formattedValue = value.toFixed(precision);
          return formattedValue;
        },
        write: function(value){
            ko.expressionRewriting.writeValueToProperty(valueAccessor(), allBindingsAccessor, 'value', value);
        }
    });
    ko.applyBindingAccessorsToNode(element, { value: function(){return formattingComputed;} }, bindingContext);
  }
}

根据官方文档,当绑定首次应用于元素时,调用一次“更新”回调,当访问的任何观察值/计算值发生变化时,调用一次“更新”回调

此外,您实际上不必同时提供init和update回调—如果您只需要提供一个或另一个回调就可以了

在下面的代码片段中,我向“marketRate”VM observable添加了一个“value”绑定,因此每当该observable发生更改时,就会触发“update”回调

ko.bindingHandlers.numericValue={
更新:函数(元素、valueAccessor、allBindings、viewModel、bindingContext){
var allBindings=ko.utils.unwrapObservable(allBindings());
if(allBindings.value()){
//使用通知精度或默认值
var precision=allBindings.numericValue.precision | | 1;
//防止四舍五入
var regex=new RegExp('^-?\\d+(?:\.\\d{0',+precision+'}');
//可观测更新
allBindings.value(parseFloat(allBindings.value().match(regex)[0]).toFixed(precision));
}
}
};
函数MyViewModel(){
//应用一些验证规则
this.marketRate=ko.observable().extend({
要求:正确,
最小:5
});
}
var vm=新的MyViewModel();
ko.应用绑定(vm)

根据官方文档,当绑定首次应用于元素时,调用一次“更新”回调,当访问的任何观察值/计算值发生变化时,调用一次“更新”回调

此外,您实际上不必同时提供init和update回调—如果您只需要提供一个或另一个回调就可以了

在下面的代码片段中,我向“marketRate”VM observable添加了一个“value”绑定,因此每当该observable发生更改时,就会触发“update”回调

ko.bindingHandlers.numericValue={
更新:函数(元素、valueAccessor、allBindings、viewModel、bindingContext){
var allBindings=ko.utils.unwrapObservable(allBindings());
if(allBindings.value()){
//使用通知精度或默认值
var precision=allBindings.numericValue.precision | | 1;
//防止四舍五入
var regex=new RegExp('^-?\\d+(?:\.\\d{0',+precision+'}');
//可观测更新
allBindings.value(parseFloat(allBindings.value().match(regex)[0]).toFixed(precision));
}
}
};
函数MyViewModel(){
//应用一些验证规则
this.marketRate=ko.observable().extend({
要求:正确,
最小:5
});
}
var vm=新的MyViewModel();
ko.应用绑定(vm)


这两种解决方案对我都有部分作用。他们不尊重我对可观察对象进行的淘汰验证,有没有办法进行格式化和验证?第二个被剪掉的部分不会为我更新基础的可观测值。在最后一行中,请尝试将计算结果包装到函数中。applybindingAccessorNode(元素,{value:function(){return formattingComputed;}},bindingContext);我已将答案更新为匹配。您的验证设置是什么样的?这是使用敲除验证插件吗?如果是的话,在ko.validation中有一个方法可以链接到您的自定义绑定。makeBindingHandlerValidable('yourBindingName');谢谢我已经用可观察性和验证性更新了我的问题。这两种解决方案对我都有一定的作用。他们不尊重我对可观察对象进行的淘汰验证,有没有办法进行格式化和验证?第二个被剪掉的部分不会为我更新基础的可观测值。在最后一行中,请尝试将计算结果包装到函数中。applybindingAccessorNode(元素,{value:function(){return formattingComputed;}},bindingContext);我已将答案更新为匹配。您的验证设置是什么样的?这是使用敲除验证插件吗?如果是的话,在ko.validation中有一个方法可以链接到您的自定义绑定。ko.validation.makeBindingHand