【问题标题】:make an input only-numeric type on knockout在淘汰赛上制作一个仅输入的数字类型
【发布时间】:2013-06-07 13:26:35
【问题描述】:

我阅读了很多教程,但我不知道如何做到这一点,这是输入

input(type="text",name="price",id="price"data-bind="text: price,valueUpdate:['afterkeydown','propertychange','input']")

这是我的视图模型

price: ko.computed(function()
{
    return parseFloat(this.replace(' ','').replace(/[^0-9\.]+/g,"")) || '';
},this)

但这会导致错误:这没有方法替换???如何将价格值传递给计算函数??

【问题讨论】:

  • input type="text"改成input type="number"会怎么样?我认为这些将您放入其中的内容限制为仅数值。
  • type="number" 对某些浏览器的兼容性较差
  • Jon 是正确的,因为您可以将类型更改为数字,但如果我没记错的话,并非所有浏览器都支持该类型。例如,我相信 IE10 之前的任何东西都可以让您将文本放在那里没有问题
  • 这对于查看兼容性很有用caniuse.com/#search=number
  • 在淘汰赛的文档中有一个关于这个的话题。您可能需要创建一个扩展程序。他们的样品实际上满足了您的要求。 knockoutjs.com/documentation/extenders.html

标签: javascript knockout.js knockout-2.0


【解决方案1】:

最好创建自定义绑定 http://knockoutjs.com/documentation/custom-bindings.html,它只接受允许的字符 [0-9,.] 作为数字表示。

把这条线放到你的视野里

<input id="text" type="text" data-bind="numeric, value: number">

将此行放入您的模型中(记住将数字绑定为可观察属性)

ko.bindingHandlers.numeric = {
    init: function (element, valueAccessor) {
        $(element).on("keydown", function (event) {
            // Allow: backspace, delete, tab, escape, and enter
            if (event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode == 13 ||
                // Allow: Ctrl+A
                (event.keyCode == 65 && event.ctrlKey === true) ||
                // Allow: . ,
                (event.keyCode == 188 || event.keyCode == 190 || event.keyCode == 110) ||
                // Allow: home, end, left, right
                (event.keyCode >= 35 && event.keyCode <= 39)) {
                // let it happen, don't do anything
                return;
            }
            else {
                // Ensure that it is a number and stop the keypress
                if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode > 105)) {
                    event.preventDefault();
                }
            }
        });
    }
};

【讨论】:

  • 这真的有效吗?对我来说,如果它在 UI 上的某个地方,它不会更新 Observable?例如,您有上面的 以及一些 。在这种情况下,如果用户在输入中编辑数字,则编辑完成后 UI 不会更新。
  • 从输入字段更改焦点后将应用更改。这是带有实时编辑的简单示例(没有焦点更改)。 jsfiddle.net/jakethashi/L7UEm
  • @renathy 我离开了 textInput 绑定,并添加了数字作为第二个绑定,效果很好
  • 您如何处理荷兰语键盘?哪里的数字是 Shift + Key ?
  • 捷克语键盘也不起作用,需要 Shift+数字才能起作用。
【解决方案2】:

另一种方法:我发现 Knockout 与 jQuery-validate 结合使用效果很好。您只需要确保在尝试使用数值之前验证表单。

假设你有一个表单 DOM 元素,你可以通过设置验证规则

$(".yourform").validate({
    rules: {
        year: {
            digits: true,
            minlength: 4,
            maxlength: 4
        }
    },
    messages: {
        year: "Please enter four digits (e.g. 2009).",
    }
});

在您的视图模型中,您像往常一样设置双向绑定,例如通过self.year = ko.observable("")。现在确保在进一步处理self.year() 之前调用$(".yourform").valid()。就我而言,我正在做var year = parseInt(self.year(), 10)。在表单验证之后,这总是会产生有意义的结果。

【讨论】:

    【解决方案3】:

    Knockout 对此有扩展器。来自 knockoutjs.com 的Check This 解释了如何使用可观察扩展器强制输入为数字。我将文档中的代码粘贴到此处:

    源代码:查看

    <p><input data-bind="value: myNumberOne" /> (round to whole number)</p>
    <p><input data-bind="value: myNumberTwo" /> (round to two decimals)</p>
    

    源代码:查看模型

    ko.extenders.numeric = function(target, precision) {
        //create a writable computed observable to intercept writes to our observable
        var result = ko.pureComputed({
            read: target,  //always return the original observables value
            write: function(newValue) {
                var current = target(),
                    roundingMultiplier = Math.pow(10, precision),
                    newValueAsNum = isNaN(newValue) ? 0 : parseFloat(+newValue),
                    valueToWrite = Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;
    
                //only write if it changed
                if (valueToWrite !== current) {
                    target(valueToWrite);
                } else {
                    //if the rounded value is the same, but a different value was written, force a notification for the current field
                    if (newValue !== current) {
                        target.notifySubscribers(valueToWrite);
                    }
                }
            }
        }).extend({ notify: 'always' });
    
        //initialize with current value to make sure it is rounded appropriately
        result(target());
    
        //return the new computed observable
        return result;
    };
    
    function AppViewModel(one, two) {
        this.myNumberOne = ko.observable(one).extend({ numeric: 0 });
        this.myNumberTwo = ko.observable(two).extend({ numeric: 2 });
    }
    
    ko.applyBindings(new AppViewModel(221.2234, 123.4525));
    

    【讨论】:

      【解决方案4】:
       <input type="text" id="alpha-validation" data-bind="value: YourDataName, valueUpdate: 'afterkeydown' , event: { 'input': AlphaCheck}" style="text-transform:uppercase">
      

      创建 AlphaCheck 函数并添加它。

          $('#alpha-validation').keyup(function () {
              if (this.value.match(/[^0-9 ]/g)) {
                  this.value = this.value.replace(/[^0-9 ]/g, '');
              }
          });
      

      这行得通!

      【讨论】:

        【解决方案5】:

        我知道这个问题已经有一年了,但为了页面的功能访问者,让我发布这个问题。

        看看这个:

        ko.bindingHandlers.numericnumbers = {
        init: function (element) {
            $(element).on('keypress', function (number) {
                number = (number) ? number : window.event;
                var charcode = (number.which) ? number.which : number.keyCode;
                if (charcode > 31 && (charcode < 48 || charcode > 75))
                    number.preventDefault();
            });
        }};
        

        【讨论】:

          【解决方案6】:

          创建指向闪亮的新代码的数据绑定:

          <input id="price" name="price" type="text" data-bind="numeric">
          

          闪亮的新淘汰码:

          price = ko.observable();
          price.subscribe(function(newValue) {
              price = newValue.replace(/[\D\.]/g, '');
          });
          

          这意味着每次更新价格时,它都会应用函数中的逻辑(在这种情况下,去掉任何不是数字或句点的东西),并将其直接应用于价格。您还可以在此处添加其他验证或很酷的功能,例如在开头添加货币 sybmol,将其保留到小数点后 2 位等...

          【讨论】:

            【解决方案7】:

            在“keydown”事件的帮助下,我们可以限制文本框中其他键的值,这些键应该包含数值。

            $(document).ready(function(){                
                    $("selector").on("keydown", function (e) {
                        //numbers, delete, backspace, arrows
                        var validKeyCodes = [8, 9, 37, 38, 39, 40, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57];
                        if (!($.inArray(e.keyCode, validKeyCodes) >= 0))
                                e.preventDefault();                 
                    });           
                });
            

            【讨论】:

              【解决方案8】:

              我们可以限制用户输入多于两位十进制数的用户 例如。 23.81, 3452.83 修改代码如下。参考代码取自@Martin Surynek 的答案。

              HTML -

              <p>
                  <input data-bind="value: myNumberOne" /> (round to whole number)</p>
                <p>
                  <input data-bind="num, value: myNumberTwo" /> (round to two decimals)</p>
              

              脚本 -

              <script>
                  ko.bindingHandlers.num = {
                    init: function (element, valueAccessor) {
                      $(element).on("keypress", function (event) {
                        //debugger
                        console.log(event.keyCode);
                        var $this = $(this);
                        var text = $this.val();
              
                        // Stop insert two dots
                        if ($this.val().indexOf('.') != -1 && (event.which == 190 || event.which == 110)) {
                          event.preventDefault();
                        }
              
                        // Allow: backspace, delete, tab, escape, and enter
                        if (event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode ==
                          13 ||
                          // Allow: Ctrl+A
                          (event.keyCode == 65 && event.ctrlKey === true) ||
                          // Allow: .   ,event.keyCode == 188 ||
                          ( event.keyCode == 190 || event.keyCode == 110) ||
                          // Allow: home, end, left, right
                          (event.keyCode >= 35 && event.keyCode <= 39)) {
                          // let it happen, don't do anything
                          return;
                        }
              
                        // Ensure that it is a number and stop the keypress
                        if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode >
                            105)) {
                          event.preventDefault();
                        }
              
                        if ((event.which == 46) && (text.indexOf('.') == -1)) {
                          setTimeout(function () {
                            if ($this.val().substring($this.val().indexOf('.')).length > 3) {
                              $this.val($this.val().substring(0, $this.val().indexOf('.') + 3));
                            }
                          }, 1);
                        }
              
                        if ((text.indexOf('.') != -1) &&
                          (text.substring(text.indexOf('.')).length > 2) &&
                          (event.which != 0 && event.which != 8) &&
                          ($(this)[0].selectionStart >= text.length - 2)) {
                          event.preventDefault();
                        }          
                        //console.log($(this)[0].selectionStart >= text.length - 2);
                      });
                    }
                  };
              
              
                  ko.extenders.numeric = function (target, precision) {
                    //create a writable computed observable to intercept writes to our observable
              
                    var result = ko.pureComputed({
                      read: target, //always return the original observables value
                      write: function (newValue) {
              
                        var current = target(),
                          roundingMultiplier = Math.pow(10, precision),
                          newValueAsNum = isNaN(newValue) ? 0 : parseFloat(+newValue),
                          valueToWrite = Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;
              
                        //only write if it changed
                        if (valueToWrite !== current) {
                          target(valueToWrite);
                        } else {
                          //if the rounded value is the same, but a different value was written, force a notification for the current field
                          if (newValue !== current) {
                            target.notifySubscribers(valueToWrite);
                          }
                        }
                      }
                    }).extend({
                      notify: 'always'
                    });
              
                    //initialize with current value to make sure it is rounded appropriately
                    result(target());
              
                    //return the new computed observable
                    return result;
                  };
              
                  function AppViewModel(one, two) {
                    this.myNumberOne = ko.observable(one).extend({
                      numeric: 0
                    });
                    this.myNumberTwo = ko.observable(two).extend({
                      numeric: 2
                    });
                  }
              
                  ko.applyBindings(new AppViewModel(221.2234, 123.4525));
                </script>
              

              【讨论】:

                【解决方案9】:

                我也遇到过类似的问题。

                我还需要只确保 inter 值,对于 IE9 及更高版本(所以 type=numberical 是不够的),并且由于我们有很多国际客户,我也不能依赖键码,所以以下是我最终得到:

                //In my js class method (self is this as usual)
                self.ensureNumberical = function (data, e) {
                    var keyValue = e.key;
                    if (keyValue.match(/[0-9]/g)) {
                        return true;
                    }
                    return false;
                }
                
                //In my MVC View
                data-bind="event: { keypress: ensureNumberical }"
                

                【讨论】:

                  【解决方案10】:

                  最适合今天的场景https://github.com/Knockout-Contrib/Knockout-Validation

                  运行下面的sn-p。输入非数字或超过 255 的内容将导致显示消息。

                  function model() {
                    var self = this;
                    this.myObj = ko.observable().extend({ digit: true }).extend({ max: 255});
                    }
                    
                    var mymodel = new model();
                  
                  $(document).ready(function() {
                    ko.validation.init();
                    ko.applyBindings(mymodel);
                  });
                  <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 src="https://cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.min.js"></script>
                  
                  enter a digit less than or equal to  255 <input type="text" data-bind="textInput: myObj">
                  
                  <p>
                    Enter something other than a digit or over 255 will cause an error.
                  </p>

                  礼貌:布莱恩·德林格:https://stackoverflow.com/a/42940109/3868653

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2013-03-31
                    • 1970-01-01
                    • 2013-04-10
                    • 2014-10-21
                    • 2014-10-13
                    • 1970-01-01
                    • 2014-05-31
                    • 2012-04-08
                    相关资源
                    最近更新 更多