AngularJS 数字输入格式化视图

Posted

技术标签:

【中文标题】AngularJS 数字输入格式化视图【英文标题】:AngularJS number input formatted view 【发布时间】:2014-07-23 00:07:52 【问题描述】:

我想在用户输入大数字时使用格式化的数字输入向用户显示千个分隔点。这是我使用的指令代码:http://jsfiddle.net/LCZfd/3/

当我使用 input type="text" 时,它可以工作,但是当我想使用 input type="number" 时,当用户输入大数字时,它会被奇怪的东西清理掉。

input[number]有什么问题?

【问题讨论】:

在 Chrome 上运行良好!您正在测试哪个浏览器? 抱歉,我分享了错误的 jsfiddle 网址。我现在更新了。 我对您要完成的工作有点困惑,但请看一下:jsfiddle.net/LCZfd/4 我使用具有type="number" 属性的表单输入。用户写大数字。我想在用户写作时用千位分隔符显示这个数字。 类似这样的东西:jsfiddle.net/LCZfd/6 【参考方案1】:

正如 cmets 中所写,input type="number" 不支持除数字、小数点分隔符(通常为 ,. 取决于区域设置)和 -e 之外的任何内容。你仍然可以输入任何你想要的,但是浏览器会丢弃任何未知/不正确的字符。

这给你留下了两个选择:

使用type="text"pattern="[0-9]+([\.,][0-9]+)*" 之类的模式验证来限制用户可以输入的内容,同时自动格式化您在your example 中所做的值。 在输入字段顶部放置一个覆盖层,以您想要的方式呈现数字,同时仍然允许用户使用自定义 type="number" 输入控件,例如 demonstrated here。

后一种解决方案使用一个额外的<label> 标记,该标记包含当前值,并在您聚焦输入字段时通过 CSS 隐藏。

【讨论】:

不错的解决方案!但似乎没有输入小数点。关于我们如何实现这一目标的任何提示都会很棒。谢谢 我们的目标是在数字中加入千位分隔符,而不是小数。支持两者要复杂得多,因为当您不知道用户的语言环境时,您不知道他们输入的是小数还是千位分隔符。我的答案的示例 2 应该适用于两者。 很好的解决方案!对于 $parsers 和 $formatters 解决方案,使用 $setViewValue 和 $render 来防止元素与视图不同步。 (如果您尝试在 jsfiddle 中重复添加双逗号,您可以看到这一点)。查看更多github.com/angular/angular.js/issues/12544。【参考方案2】:

这么多年过去了,仍然没有现成的 html5 解决方案。

我正在使用<input type="tel"><input type="text">(“tel”在 androidios 中会显示一个数字键盘,在某些情况下这是一个奖励。)

然后我需要一个指令来:

过滤掉非数字字符 在用户输入时添加千位分隔符 使用$parserskeyup设置elem.val()$formatters设置显示... ...在幕后,为ng-model分配一个浮点数

下面的指令示例执行此操作,它接受负数和浮点数,除非您指定只需要正数或整数。

这不是我想要的完整解决方案,但我认为它弥补了差距。

HTML

<input type="text" ng-model="someNumber" number-input />

javascript

myApp.directive('numberInput', function($filter) 
  return 
    require: 'ngModel',
    link: function(scope, elem, attrs, ngModelCtrl) 

      ngModelCtrl.$formatters.push(function(modelValue) 
        return setDisplayNumber(modelValue, true);
      );

      // it's best to change the displayed text using elem.val() rather than
      // ngModelCtrl.$setViewValue because the latter will re-trigger the parser
      // and not necessarily in the correct order with the changed value last.
      // see http://radify.io/blog/understanding-ngmodelcontroller-by-example-part-1/
      // for an explanation of how ngModelCtrl works.
      ngModelCtrl.$parsers.push(function(viewValue) 
        setDisplayNumber(viewValue);
        return setModelNumber(viewValue);
      );

      // occasionally the parser chain doesn't run (when the user repeatedly 
      // types the same non-numeric character)
      // for these cases, clean up again half a second later using "keyup"
      // (the parser runs much sooner than keyup, so it's better UX to also do it within parser
      // to give the feeling that the comma is added as they type)
      elem.bind('keyup focus', function() 
        setDisplayNumber(elem.val());
      );
      function setDisplayNumber(val, formatter) 
        var valStr, displayValue;

        if (typeof val === 'undefined') 
          return 0;
        

        valStr = val.toString();
        displayValue = valStr.replace(/,/g, '').replace(/[A-Za-z]/g, '');
        displayValue = parseFloat(displayValue);
        displayValue = (!isNaN(displayValue)) ? displayValue.toString() : '';

        // handle leading character -/0
        if (valStr.length === 1 && valStr[0] === '-') 
          displayValue = valStr[0];
         else if (valStr.length === 1 && valStr[0] === '0') 
          displayValue = '';
         else 
          displayValue = $filter('number')(displayValue);
        
        // handle decimal
        if (!attrs.integer) 
          if (displayValue.indexOf('.') === -1) 
            if (valStr.slice(-1) === '.') 
              displayValue += '.';
             else if (valStr.slice(-2) === '.0') 
              displayValue += '.0';
             else if (valStr.slice(-3) === '.00') 
              displayValue += '.00';
            
           // handle last character 0 after decimal and another number
          else 
            if (valStr.slice(-1) === '0') 
              displayValue += '0';
            
          
        

        if (attrs.positive && displayValue[0] === '-') 
          displayValue = displayValue.substring(1);
        

        if (typeof formatter !== 'undefined') 
          return (displayValue === '') ? 0 : displayValue;
         else 
          elem.val((displayValue === '0') ? '' : displayValue);
        
      
      function setModelNumber(val) 
        var modelNum = val.toString().replace(/,/g, '').replace(/[A-Za-z]/g, '');
        modelNum = parseFloat(modelNum);
        modelNum = (!isNaN(modelNum)) ? modelNum : 0;
        if (modelNum.toString().indexOf('.') !== -1) 
          modelNum = Math.round((modelNum + 0.00001) * 100) / 100;
        
        if (attrs.positive) 
          modelNum = Math.abs(modelNum);
        
        return modelNum;
      
    
  ;
);

https://jsfiddle.net/benlk/4dto9738/

【讨论】:

【参考方案3】:

你可以试试这个,我修改了我在这里看到的指令...... How do I restrict an input to only accept numbers? ...

这是我修改后的指令...该指令使用 keyup 事件即时修改输入...

.directive('numericOnly', function($filter) 
 return 
  require: 'ngModel',
  link: function(scope, element, attrs, modelCtrl) 

       element.bind('keyup', function (inputValue, e) 
         var strinput = modelCtrl.$$rawModelValue;
         //filter user input
         var transformedInput = strinput ? strinput.replace(/[^,\d.-]/g,'') : null;
         //remove trailing 0
         if(transformedInput.charAt(0) <= '0')
           transformedInput = null;
           modelCtrl.$setViewValue(transformedInput);
           modelCtrl.$render();
         else
           var decimalSplit = transformedInput.split(".")
           var intPart = decimalSplit[0];
           var decPart = decimalSplit[1];
           //remove previously formated number
           intPart = intPart.replace(/,/g, "");
           //split whole number into array of 3 digits
           if(intPart.length > 3)
             var intDiv = Math.floor(intPart.length / 3);
             var strfraction = [];
             var i = intDiv,
                 j = 3;

             while(intDiv > 0)
               strfraction[intDiv] = intPart.slice(intPart.length-j,intPart.length - (j - 3));
               j=j+3;
               intDiv--;
             
             var k = j-3;
             if((intPart.length-k) > 0)
               strfraction[0] = intPart.slice(0,intPart.length-k);
             
           
           //join arrays
           if(strfraction == undefined) return;
             var currencyformat = strfraction.join(',');
             //check for leading comma
             if(currencyformat.charAt(0)==',')
               currencyformat = currencyformat.slice(1);
             

             if(decPart ==  undefined)
               modelCtrl.$setViewValue(currencyformat);
               modelCtrl.$render();
               return;
             else
               currencyformat = currencyformat + "." + decPart.slice(0,2);
               modelCtrl.$setViewValue(currencyformat);
               modelCtrl.$render();
             
         
        );
  

;

你是这样用的……

<input type="text" ng-model="amountallocated" id="amountallocated" numeric-only />

【讨论】:

【参考方案4】:

, 不能使用值,因为 type=number 只接受数字,添加逗号使其成为字符串。

见http://jsfiddle.net/LCZfd/5

如果您需要逗号,最好自己制作控件。一个有一个真值(数字)和一个显示值(字符串)。

【讨论】:

有趣的是,我可以通过键入在type=number 中写入“1,000,000”,但如果我通过 ng-model 设置它,它会删除所有内容。这对我来说似乎有些麻烦。你觉得正常吗? 是的,这很奇怪。手动输入“50,000”即可。在内部,它将 value 和 valueAsNumber 设置为 50000,但它会显示 50,000,并且按向上/向下箭头会删除逗号。【参考方案5】:

您需要将step 属性添加到您的number 输入中。

<input type="number" step="0.01" />

这将允许浮点数。

http://jsfiddle.net/LCZfd/1/

另外,我建议查看 Firefox 中 number 输入的错误线程。您可能需要考虑使用此输入类型,因为它刚刚在 FF 版本中得到支持。

https://bugzilla.mozilla.org/show_bug.cgi?id=344616 http://caniuse.com/input-number

【讨论】:

抱歉,我分享了错误的 jsfiddle 网址。我用真实的问题更新了问题。所以我的问题不在于浮点数。我想使用千位分隔符,例如“1,000,000”

以上是关于AngularJS 数字输入格式化视图的主要内容,如果未能解决你的问题,请参考以下文章

angularjs 判断字符串是不是是数字格式

在Angularjs中格式化输入值

AngularJS-03 过滤器

Vue.Js 2 输入格式化数字

angularjs

AngularJS学习之旅—AngularJS 过滤器