Skip to content

Commit 0ae78f1

Browse files
committed
initial commit
0 parents  commit 0ae78f1

18 files changed

+1063
-0
lines changed

.gitattributes

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/bower_components
2+
/node_modules
3+
/temp
4+
/.idea
5+
/.tmp
6+
.DS_Store
7+
*~

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/bower_components
2+
/node_modules
3+
/temp
4+
/.idea
5+
/.tmp
6+
.DS_Store
7+
*~

.travis.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
language: node_js
2+
node_js:
3+
- 4

LICENSE

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2013-2016 angular-numeric-input
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
this software and associated documentation files (the "Software"), to deal in
7+
the Software without restriction, including without limitation the rights to
8+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+
the Software, and to permit persons to whom the Software is furnished to do so,
10+
subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
[![Bower Version](https://img.shields.io/bower/v/angular-numeric-input.svg?style=flat)](https://github.com/changLiuUNSW/angular-numeric-input/releases) [![NPM Version](http://img.shields.io/npm/v/angular-numeric-input.svg?style=flat)](https://www.npmjs.org/package/angular-numeric-input) [![Build Status](https://travis-ci.org/changLiuUNSW/angular-numeric-input.svg?branch=master)](https://travis-ci.org/changLiuUNSW/angular-numeric-input)
2+
3+
# Angular-numeric-input
4+
An Angular directive for number input to provide real-time number input formatting and validations.
5+
6+
It does a few things:
7+
8+
- Real-time number input formatting
9+
- Support decimal (max 2 decimal places) and positive integer number
10+
- Support dynamic Min and Max validation
11+
- Support Maximum length validation (default to 9)
12+
13+
**Note** Not suport negative number.
14+
15+
## Usage:
16+
17+
```
18+
bower install angular-numeric-input
19+
```
20+
21+
22+
Load the unminified or minified file from `dist` dir:
23+
24+
```
25+
<script src="dist/angular-numeric-input.js"></script>
26+
```
27+
28+
Then include it as a dependency in your app.
29+
30+
```
31+
angular.module('myApp', ['ui.numericInput'])
32+
```
33+
34+
35+
### Attributes:
36+
37+
- `ng-model`: _required_
38+
- `type`: Set to `text` or `tel` or just leave it out. Do _not_ set to `number`.
39+
- `min`: _optional_ Defaults to `1`.
40+
- `max`: _optional_ Not enforced by default
41+
- `max-length`: _optional_ Defaults to `9`
42+
- `allow-decimal`: _optional_ Defaults to `false` (Postive Integer)
43+
- `min-not-equal`: _optional_ Defaults to `false`
44+
- `max-not-equal`: _optional_ Defaults to `false`
45+
46+
Basic example:
47+
48+
``` html
49+
<input type="tel" ng-model="model" data-numeric-input>
50+
```
51+
52+
`min`, `max` can be set dynamically:
53+
54+
``` html
55+
<input type="tel" data-numeric-input data-ng-model="model" data-max-length="10" data-min="{{min}}" data-max="{{max}}"/>
56+
```
57+
58+
## Tests:
59+
60+
1. Install test deps: `npm install`
61+
1. Run: `gulp test`

bower.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "angular-numeric-input",
3+
"homepage": "https://github.com/changLiuUNSW/angular-numeric-input",
4+
"author": "Chang Liu <[email protected]>",
5+
"description": "AngularJS directive to provide real-time number formatting and validations",
6+
"version": "1.0.0",
7+
"main": [
8+
"dist/angular-numeric-input.js"
9+
],
10+
"license": "MIT",
11+
"keywords": [
12+
"angular directive",
13+
"angular",
14+
"currency",
15+
"input",
16+
"number",
17+
"real time",
18+
"format"
19+
],
20+
"ignore": [
21+
"**/.*",
22+
"node_modules",
23+
"bower_components",
24+
"src",
25+
"test",
26+
"gulpfile.js",
27+
"karma.conf.js",
28+
"examples"
29+
],
30+
"dependencies": {
31+
"angular": ">=1.3.0"
32+
}
33+
}

dist/angular-numeric-input.js

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
(function() {
2+
'use strict';
3+
4+
angular.module('ui.numericInput', [])
5+
.directive('uiNumericInput', ['$filter', function($filter) {
6+
return {
7+
restrict: 'A',
8+
require: 'ngModel',
9+
link: function(scope, el, attrs, ngModelCtrl) {
10+
var NUMBER_REGEXP = /^\s*[-+]?(\d+|\d*\.\d*)\s*$/,
11+
min = 1,
12+
max,
13+
lastValidValue,
14+
dotSuffix,
15+
positiveInteger = true,
16+
minNotEqual,
17+
maxNotEqual,
18+
maxLength = 9,
19+
precision = 0;
20+
21+
if (attrs.maxLength >= 1) {
22+
maxLength = attrs.maxLength;
23+
}
24+
25+
if (attrs.allowDecimal) {
26+
positiveInteger = false;
27+
precision = 2;
28+
min = 0;
29+
}
30+
31+
if (attrs.minNotEqual) {
32+
minNotEqual = true;
33+
}
34+
35+
if (attrs.maxNotEqual) {
36+
maxNotEqual = true;
37+
}
38+
39+
/**
40+
* Returns a rounded number in the precision setup by the directive
41+
* @param {Number} num Number to be rounded
42+
* @return {Number} Rounded number
43+
*/
44+
function round(value) {
45+
var num = parseFloat(value);
46+
var d = Math.pow(10, precision);
47+
return Math.round(num * d) / d;
48+
}
49+
50+
/**
51+
* Returns a string that represents the rounded number
52+
* @param {Number} value Number to be rounded
53+
* @return {String} The string representation
54+
*/
55+
function formatPrecision(value) {
56+
return parseFloat(value).toFixed(precision);
57+
}
58+
59+
function getCommaCount(value) {
60+
var length = 0;
61+
var matchResult = (value + '').match(/,/g);
62+
if (matchResult) {
63+
length = matchResult.length;
64+
}
65+
return length;
66+
}
67+
68+
//Convert to String
69+
function formatViewValue(value) {
70+
return ngModelCtrl.$isEmpty(value) ? '' : '' + value;
71+
}
72+
73+
function formatToNumber(value) {
74+
return $filter('number')(value);
75+
}
76+
77+
function numberLength(value) {
78+
var length = 0;
79+
var matchResult = (value + '').match(/\d/g);
80+
if (matchResult) {
81+
length = matchResult.length;
82+
}
83+
return length;
84+
}
85+
86+
function minValidator(value) {
87+
var invalid = minNotEqual ? value <= min : value < min;
88+
if (!ngModelCtrl.$isEmpty(value) && invalid) {
89+
ngModelCtrl.$setValidity('min', false);
90+
} else {
91+
ngModelCtrl.$setValidity('min', true);
92+
}
93+
return value;
94+
}
95+
96+
function maxValidator(value) {
97+
var invalid = maxNotEqual ? value >= max : value > max;
98+
if (!ngModelCtrl.$isEmpty(value) && invalid) {
99+
ngModelCtrl.$setValidity('max', false);
100+
} else {
101+
ngModelCtrl.$setValidity('max', true);
102+
103+
}
104+
return value;
105+
}
106+
107+
ngModelCtrl.$parsers.push(function(input) {
108+
//check undefined and NaN
109+
//http://adripofjavascript.com/blog/drips/the-problem-with-testing-for-nan-in-javascript.html
110+
if (angular.isUndefined(input) || (input !== input)) {
111+
input = '';
112+
}
113+
114+
var value = input.replace(/\,/g, '');
115+
var lastChar = value.substr(value.length - 1);
116+
if (!positiveInteger) {
117+
dotSuffix = lastChar === '.' ? true : false;
118+
}
119+
120+
// Handle leading decimal point, like ".5"
121+
if (value.indexOf('.') === 0) {
122+
value = '0' + value;
123+
}
124+
125+
var empty = ngModelCtrl.$isEmpty(value);
126+
if (empty || (NUMBER_REGEXP.test(value) && numberLength(value) <= maxLength)) {
127+
lastValidValue = (value === '') ? null : (empty ? value : round(value));
128+
} else {
129+
// Render the last valid input in the field
130+
ngModelCtrl.$setViewValue(formatViewValue(lastValidValue));
131+
ngModelCtrl.$render();
132+
}
133+
ngModelCtrl.$setValidity('numeric', !dotSuffix);
134+
return lastValidValue;
135+
});
136+
137+
ngModelCtrl.$formatters.push(formatToNumber);
138+
139+
// Min validation (optional)
140+
attrs.$observe('min', function(value) {
141+
min = parseFloat(value || min);
142+
minValidator(ngModelCtrl.$modelValue);
143+
});
144+
145+
ngModelCtrl.$parsers.push(minValidator);
146+
ngModelCtrl.$formatters.push(minValidator);
147+
148+
// Max validation (optional)
149+
if (angular.isDefined(attrs.max)) {
150+
attrs.$observe('max', function(val) {
151+
max = parseFloat(val);
152+
maxValidator(ngModelCtrl.$modelValue);
153+
});
154+
ngModelCtrl.$parsers.push(maxValidator);
155+
ngModelCtrl.$formatters.push(maxValidator);
156+
}
157+
158+
ngModelCtrl.$formatters.push(function(value) {
159+
return value ? formatPrecision(value) : value;
160+
});
161+
162+
//Formatting must be the last of $parser pipeline
163+
ngModelCtrl.$parsers.push(function(value) {
164+
//This section is for decimal values if positiveInteger flag is false
165+
var viewValue = formatToNumber(value);
166+
if (!positiveInteger && dotSuffix) {
167+
viewValue += '.';
168+
}
169+
//This logic is used to preserve cursor position after formatting
170+
var start = el[0].selectionStart,
171+
end = el[0].selectionEnd,
172+
oldViewValue = ngModelCtrl.$viewValue;
173+
if (getCommaCount(oldViewValue) > getCommaCount(viewValue)) {
174+
start--;
175+
end--;
176+
}
177+
if (getCommaCount(oldViewValue) < getCommaCount(viewValue)) {
178+
start++;
179+
end++;
180+
}
181+
//Do not use $setViewValue to set viewValue here, because it will trigger $parse pipeline.
182+
ngModelCtrl.$viewValue = viewValue;
183+
ngModelCtrl.$render();
184+
el[0].setSelectionRange(start, end);
185+
return value;
186+
});
187+
}
188+
};
189+
}]);
190+
})();

dist/angular-numeric-input.min.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)