How do I restrict an input to only accept numbers?

前端 未结 17 1224
感情败类
感情败类 2020-12-07 09:28

I am using ngChange in AngularJS to trigger a custom function that will remove any letters the user adds to the input.



        
相关标签:
17条回答
  • 2020-12-07 10:16

    you may also want to remove the 0 at the beginning of the input... I simply add an if block to Mordred answer above because I cannot make a comment yet...

      app.directive('numericOnly', function() {
        return {
          require: 'ngModel',
          link: function(scope, element, attrs, modelCtrl) {
    
              modelCtrl.$parsers.push(function (inputValue) {
                  var transformedInput = inputValue ? inputValue.replace(/[^\d.-]/g,'') : null;
    
                  if (transformedInput!=inputValue) {
                      modelCtrl.$setViewValue(transformedInput);
                      modelCtrl.$render();
                  }
                  //clear beginning 0
                  if(transformedInput == 0){
                    modelCtrl.$setViewValue(null);
                    modelCtrl.$render();
                  }
                  return transformedInput;
              });
          }
        };
      })
    
    0 讨论(0)
  • 2020-12-07 10:19

    I know this is old, but I've created a directive for this purpose in case anyone is looking for an easy solution. Very simple to use.

    You can check it out here.

    0 讨论(0)
  • 2020-12-07 10:19

    I ended up creating a modified directive of the above code to accept input and change the format on the fly...

    .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();
                     }
                 }
                });
          }
      };
    

    })

    0 讨论(0)
  • 2020-12-07 10:25

    All the above solutions are quite large, i wanted to give my 2 cents on this.

    I am only checking if the value inputed is a number or not, and checking if it's not blank, that's all.

    Here is the html:

    <input type="text" ng-keypress="CheckNumber()"/>
    

    Here is the JS:

    $scope.CheckKey = function () {
        if (isNaN(event.key) || event.key === ' ' || event.key === '') {
            event.returnValue = '';
        }
    };
    

    It's quite simple.

    I belive this wont work on Paste tho, just so it's known.

    For Paste, i think you would need to use the onChange event and parse the whole string, quite another beast the tamme. This is specific for typing.

    UPDATE for Paste: just add this JS function:

    $scope.CheckPaste = function () {
        var paste = event.clipboardData.getData('text');
    
        if (isNaN(paste)) {
            event.preventDefault();
            return false;
        }
    };
    

    And the html input add the trigger:

    <input type="text" ng-paste="CheckPaste()"/>
    

    I hope this helps o/

    0 讨论(0)
  • 2020-12-07 10:26

    Here is a Plunker handling any situation above proposition do not handle.
    By using $formatters and $parsers pipeline and avoiding type="number"

    And here is the explanation of problems/solutions (also available in the Plunker) :

    /*
     *
     * Limit input text for floating numbers.
     * It does not display characters and can limit the Float value to X numbers of integers and X numbers of decimals.
     * min and max attributes can be added. They can be Integers as well as Floating values.
     *
     * value needed    |    directive
     * ------------------------------------
     * 55              |    max-integer="2"
     * 55.55           |    max-integer="4" decimal="2" (decimals are substracted from total length. Same logic as database NUMBER type)
     *
     *
     * Input type="number" (HTML5)
     *
     * Browser compatibility for input type="number" :
     * Chrome : - if first letter is a String : allows everything
     *          - if first letter is a Integer : allows [0-9] and "." and "e" (exponential)
     * Firefox : allows everything
     * Internet Explorer : allows everything
     *
     * Why you should not use input type="number" :
     * When using input type="number" the $parser pipeline of ngModel controller won't be able to access NaN values.
     * For example : viewValue = '1e'  -> $parsers parameter value = "".
     * This is because undefined values are not allowes by default (which can be changed, but better not do it)
     * This makes it impossible to modify the view and model value; to get the view value, pop last character, apply to the view and return to the model.
     *
     * About the ngModel controller pipelines :
     * view value -> $parsers -> model value
     * model value -> $formatters -> view value
     *
     * About the $parsers pipeline :
     * It is an array of functions executed in ascending order.
     * When used with input type="number" :
     * This array has 2 default functions, one of them transforms the datatype of the value from String to Number.
     * To be able to change the value easier (substring), it is better to have access to a String rather than a Number.
     * To access a String, the custom function added to the $parsers pipeline should be unshifted rather than pushed.
     * Unshift gives the closest access to the view.
     *
     * About the $formatters pipeline :
     * It is executed in descending order
     * When used with input type="number"
     * Default function transforms the value datatype from Number to String.
     * To access a String, push to this pipeline. (push brings the function closest to the view value)
     *
     * The flow :
     * When changing ngModel where the directive stands : (In this case only the view has to be changed. $parsers returns the changed model)
     *     -When the value do not has to be modified :
     *     $parsers -> $render();
     *     -When the value has to be modified :
     *     $parsers(view value) --(does view needs to be changed?) -> $render();
     *       |                                  |
     *       |                     $setViewValue(changedViewValue)
     *       |                                  |
     *       --<-------<---------<--------<------
     *
     * When changing ngModel where the directive does not stand :
     *     - When the value does not has to be modified :
     *       -$formatters(model value)-->-- view value
     *     -When the value has to be changed
     *       -$formatters(model vale)-->--(does the value has to be modified) -- (when loop $parsers loop is finished, return modified value)-->view value
     *                                              |
     *                                  $setViewValue(notChangedValue) giving back the non changed value allows the $parsers handle the 'bad' value
     *                                               |                  and avoids it to think the value did not changed
     *                Changed the model <----(the above $parsers loop occurs)
     *
     */
    
    0 讨论(0)
提交回复
热议问题