2016-08-10 128 views
3

我試圖創建輸入文本指令,它只接受特定範圍內的數字。我試着解析整數的值,當然minmax沒有工作。只允許範圍內的數字輸入到文本框

我不想使用input [type =「number」]。
最終,我試圖創建一個出生日期自由輸入文本字段。 像一個如下圖所示:

date-of-birth.png

我已經適應該指令[我正在嘗試在目前使用方法] - 原來可以發現@angularjs: allows only numbers to be typed into a text box

app.directive('onlyDigits', function() { 
    return { 
     restrict: 'A', 
     require: '?ngModel', 
     link: function (scope, element, attrs, modelCtrl) { 
      modelCtrl.$parsers.push(function (inputValue) { 
       if (inputValue == undefined) return ''; 
       var transformedInput = inputValue.replace(/[^0-9]/g, ''); 
       var theInt = parseInt(transformedInput); 
       if (transformedInput !== inputValue) { 
        modelCtrl.$setViewValue(transformedInput); 
        modelCtrl.$render(); 
       } 
       return theInt; 
      }); 
     } 
    }; 

什麼我希望在解決這個問題後,我會做一個有條件的ng-show,以顯示span元素的錯誤 - 當用戶輸入的值超過31(對於白天)12(對於月)等等。

我歡迎任何建議。

謝謝。

+0

什麼是你不想要'類型= 「數字」'的原因是什麼?由於數字輸入中出現微小的滾動按鈕? – oKonyk

+0

嗨,感謝您的留言。不,我可以用CSS隱藏這些。因爲'minlength'和'maxlength'' attrs'不能和'type =「number」'一起工作,如果我手動使用這些attrs,那麼需要通過jQuery進行更多的DOM操作,所以我試着看如果在輸入類型保持爲「文本」的情況下做到這一點,會有更多的角度。 –

+0

如果你想讓提交的文本充當數字字段,我確實有一個解決方案,但不是以角度的方式,而是以JavaScript的方式,所有你需要做的就是檢查你的charCode是否在你指定的範圍內。如果你想讓我可以在這裏獲得代碼 –

回答

3

我有完全相同的問題。我嘗試了「一切」,以便使用戶友好且不接受無效值。最後,我放棄了顯然簡單的解決方案,如ng-pattern,並在朋友@Teemu Turkia的幫助下,我們提出了integers-only指令。

它採用type="text",同時支持minmax,不接受超出數字字符和-(作爲第一個字符的情況下,最低爲負)中鍵入。

此外,ng-model永遠不會分配無效值,如空字符串或NaN,只有給定範圍或null之間的值。

我知道,起初它看起來相當嚇人;)

HTML

// note: uses underscore.js 
<body> 
    <form name="form"> 
    <header>DD/MM/YYYY</header> 
    <section> 
     <input type="text" 
      name="day" 
      ng-model="day" 
      min="1" 
      max="31" 
      integers-only> 
     <input type="text" 
      name="month" 
      ng-model="month" 
      min="1" 
      max="12" 
      integers-only> 
     <input type="text" 
      name="year" 
      ng-model="year" 
      min="1900" 
      max="2016" 
      integers-only> 
    </section> 
    <section> 
     <span ng-show="form.day.$invalid">Invalid day</span> 
     <span ng-show="form.month.$invalid">Invalid month</span> 
     <span ng-show="form.year.$invalid">Invalid year</span> 
    </section> 
    </form> 
</body> 

的JavaScript

/** 
* numeric input 
* <input type="text" name="name" ng-model="model" min="0" max="100" integers-only> 
*/ 
angular.module('app', []) 
.directive('integersOnly', function() { 
    return { 
    restrict: 'A', 
    require: 'ngModel', 
    scope: { 
     min: '=', 
     max: '=' 
    }, 
    link: function(scope, element, attrs, modelCtrl) { 
     function isInvalid(value) { 
     return (value === null || typeof value === 'undefined' || !value.length); 
     } 

     function replace(value) { 
     if (isInvalid(value)) { 
      return null; 
     } 

     var newValue = []; 
     var chrs = value.split(''); 
     var allowedChars = ['0','1','2','3','4','5','6','7','8','9','-']; 

     for (var index = 0; index < chrs.length; index++) { 
      if (_.contains(allowedChars, chrs[index])) { 
      if (index > 0 && chrs[index] === '-') { 
       break; 
      } 
      newValue.push(chrs[index]); 
      } 
     } 

     return newValue.join('') || null; 
     } 

     modelCtrl.$parsers.push(function(value) { 
     var originalValue = value; 

     value = replace(value); 

     if (value !== originalValue) { 
      modelCtrl.$setViewValue(value); 
      modelCtrl.$render(); 
     } 

     return value && isFinite(value) ? parseInt(value) : value; 
     }); 

     modelCtrl.$formatters.push(function(value) { 
     if (value === null || typeof value === 'undefined') { 
      return null; 
     } 

     return parseInt(value); 
     }); 
     modelCtrl.$validators.min = function(modelValue) { 
     if (scope.min !== null && modelValue !== null && modelValue < scope.min) { return false; } 
     return true; 
     }; 
     modelCtrl.$validators.max = function(modelValue) { 
     if (scope.max !== null && modelValue !== null && modelValue > scope.max) { return false; } 
     return true; 
     }; 
     modelCtrl.$validators.hasOnlyChar = function(modelValue) { 
     if (!isInvalid(modelValue) && modelValue === '-') { return false; } 
     return true; 
     }; 
    } 
    }; 
}); 

結果

image


相關plunker這裏http://plnkr.co/edit/mIiKuw

+1

非常感謝你的幫助@Mikko!,你是一個天才! **這個工作就像一個魅力!** 給其他人使用這個,下載[underscore.js](http://underscorejs.org/),以便'_.contains()'函數在指令內工作! –

0

該解決方案使用最小和最大的屬性來限制輸入字段的值。它還使用ngModelOptions只在定義的時間間隔後更新模型值。這是爲了讓用戶在模型解析器作用於輸入之前輸入值。

angular.module("app", []); 
 
angular.module("app").directive('onlyDigits', function() { 
 
    return { 
 
    restrict: 'A', 
 
    require: '?ngModel', 
 
    scope: { 
 
     min: "@", 
 
     max: "@" 
 
    }, 
 
    link: function(scope, element, attrs, modelCtrl) { 
 
     modelCtrl.$parsers.push(function(inputValue) { 
 
     if (inputValue == undefined) return ''; 
 
     var transformedInput = inputValue.replace(/[^0-9]/g, ''); 
 
     var theInt = parseInt(transformedInput); 
 
     var max = scope.max; 
 
     var min = scope.min; 
 
     if (theInt > max) { 
 
      theInt = max; 
 
     } else if (theInt < min) { 
 
      theInt = min; 
 
     } 
 
     modelCtrl.$setViewValue(theInt.toString()); 
 
     modelCtrl.$render(); 
 
     return theInt; 
 
     }); 
 
    } 
 
    } 
 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script> 
 

 
<body ng-app="app"> 
 
    <input type="text" ng-model="month" ng-model-options="{ debounce: 200 }" only-digits min="1" max="12"> 
 
    <input type="text" ng-model="day" ng-model-options="{ debounce: 200 }" min="1" max="30" only-digits> 
 
    <input type="text" ng-model="year" ng-model-options="{ debounce: 500 }" only-digits min="1900" max="2050"> 
 

 
</body>

2

這裏是沒有任何自定義指令的解決方案。它仍然是input type="number",但實現了所需的功能。

這裏是plunker

<!DOCTYPE html> 
 
<html> 
 
    <head></head> 
 

 
    <body ng-app="app" ng-controller="dobController as dob"> 
 
    <h3>Date of birth form</h3> 
 
    <form name="dobForm" class="form" novalidate=""> 
 
     <div> 
 
      <label for="date">DD</label> 
 
      <input type="number" ng-model="dob.date" name="date" min="1" max="31" integer /> 
 
      <label for="month">MM</label> 
 
      <input type="number" ng-model="dob.month" name="month" min="1" max="12" integer /> 
 
      <label for="year">YYYY</label> 
 
      <input type="number" ng-model="dob.year" name="year" min="1900" max="2016" integer /> 
 
      
 
      <div style="color: red;" ng-if="dobForm.$invalid"> 
 
       <p ng-show="dobForm.date.$error.min || dobForm.date.$error.max"> 
 
       date must be in range 1 to 31! 
 
       </p> 
 
       <p ng-show="dobForm.month.$error.min || dobForm.month.$error.max"> 
 
       month must be in range 1 to 12! 
 
       </p> 
 
       <p ng-show="dobForm.year.$error.min || dobForm.year.$error.max"> 
 
       year must be in range 1900 to 2016! 
 
       </p> 
 
      </div> 
 
      
 
      </div> 
 
    </form> 
 
    
 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script> 
 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular-messages.js"></script> 
 
    <script> 
 
     var app = angular.module('app', []); 
 

 
     app.controller('dobController', function($scope) {}); 
 
    </script> 
 
    <style> 
 
     input[type=number]::-webkit-inner-spin-button, 
 
     input[type=number]::-webkit-outer-spin-button { 
 
      -webkit-appearance: none; 
 
      margin: 0; 
 
     } 
 
    </style> 
 
    
 
    </body> 
 

 
</html>

enter image description here

+0

這就是爲什麼這麼難!我的意思是這是很好的解決方案,但它仍然接受連續輸入'+'和'-'來輸入$ error,同時輸入'.'和','。見這裏http://i.imgur.com/MsqGQ38.png –

+0

是的,我完全同意這一點。接受的解決方案更全面。 – oKonyk