Character limit on input text - angularjs

I want to my textbox to only allow numbers and also have a character limit on it.
Currently, I have the numbers working... Now I am having issues figuring out how to limit the characters.
Here is what I have...
JS:
app.directive('numbersonly', function () {
return {
restrict: 'A',
link: function (scope, elm, attrs, ctrl) {
elm.on('keydown', function (event) {
if (event.which == 64 || event.which == 16 && elm.val().length > 4) {
return false;
} else if (event.which >= 48 && event.which <= 57) {
return true;
} else if (event.which >= 96 && event.which <= 105) {
return true;
} else if ([8, 13, 27, 37, 38, 39, 40].indexOf(event.which) > -1 && elm.val().length > 4) {
return true;
} else {
event.preventDefault();
return false;
}
});
}
}
});
Markup:
<input type="text" id="txtEmpAge" data-ng-model="newemployee.Age" class="form-control" numbersonly required />

In html input attribute length. we can use it in multiple forms:
Length, Minlength and maxlength
Try this
maxlength="5"

I had the same issue and wrote a directive to figure it all out. Then I found a plug in called angular-dynamic-number and it worked for me right out the box. I would suggest you use that if it meets your need.
https://www.npmjs.com/package/angular-dynamic-number

Related

AngularJS: Cursor is moving to last position when model is transformed

I am using zipcode directive which is accepting 9 digit US zip code and formatting it.
app.directive('formatZipCode', function () {
return {
require: 'ngModel',
link: function (scope, element, attr, ngModelCtrl) {
function fromUser(text) {
if (text) {
var transformedInput = text.replace(/[^0-9]/g, '');
if (transformedInput.length > 9) {
transformedInput = transformedInput.slice(0, 9);
}
if (transformedInput.length > 5) {
transformedInput = transformedInput.slice(0, 5) + "-" + transformedInput.slice(5);
}
if (transformedInput !== text) {
ngModelCtrl.$setViewValue(transformedInput);
ngModelCtrl.$render();
}
return transformedInput;
}
return undefined;
}
ngModelCtrl.$parsers.push(fromUser);
}
};
});
when I am removing any number from zipcode, cursor position moves back to last position.
When I delete third number cursor moves to last number
How to retain the cursor position?
Your best option is to use ng-model-options to change when the input updates (and thus runs your formatter).
This is a case where you will sacrifice live reformatting in favor of form usability.
Either use
<input type="text" ng-model="zipcode" ng-model-options="{ updateOn: 'blur' }" format-zip-code />
to update when the user leaves the field, or
<input type="text" ng-model="zipcode" ng-model-options="{ debounce: 1000 }" format-zip-code />
to update after 1s. This option will still show the cursor moving to the end of the input after the update, but not instantly.
I have resolved this by using caret position. Remember the caret position and after formatting input assign the caret position again.
app.directive('formatZipCode', function () {
return {
require: 'ngModel',
link: function (scope, element, attr, ngModelCtrl) {
function fromUser(text) {
if (text) {
var transformedInput = text.replace(/[^0-9]/g, '');
if (transformedInput.length > 9) {
transformedInput = transformedInput.slice(0, 9);
}
var caretPosition = element[0].selectionStart || undefined;
if (transformedInput.length > 5) {
var realposition = caretPosition == 6 ? caretPosition + 1 : caretPosition;
transformedInput = transformedInput.slice(0, 5) + "-" + transformedInput.slice(5);
}
if (transformedInput !== text) {
ngModelCtrl.$setViewValue(transformedInput);
ngModelCtrl.$render();
if (typeof caretPosition === 'number') {
element[0].selectionStart = element[0].selectionEnd = realposition || caretPosition;
}
else {
element[0].selectionStart = element[0].selectionEnd = 0;
}
}
return transformedInput;
}
return undefined;
}
ngModelCtrl.$parsers.push(fromUser);
}
};
});

Restrict user to allow only 10 digit number in input box

I just want to restrict user to input only 10 digits in a mobile number field.
I have tried this code
app.directive('allowOnlyNumbers', function () {
return {
restrict: 'A',
link: function (scope, elm, attrs, ctrl) {
elm.on('keydown', function (event) {
if (event.which == 64 || event.which == 16) {
// to allow numbers
return false;
} else if (event.which >= 48 && event.which <= 57) {
// to allow numbers
return true;
} else if (event.which >= 96 && event.which <= 105) {
// to allow numpad number
return true;
} else if ([8, 13, 27, 37, 38, 39, 40].indexOf(event.which) > -1) {
// to allow backspace, enter, escape, arrows
return true;
} else {
event.preventDefault();
// to stop others
return false;
}
});
}
}
});
This code allow users to input the numbers but it's taking more than 10 digits.
can anyone tell me how to restrict ofr only 10 digits only?
Any help will be appreciated.
Thanks in advance....
You could also try using ng-pattern:
<input type="text" class="form-control" ng-model="sample"
ng-pattern="/^[0-9]{10}$/">
This would require exactly 10 digits, and nothing else, for validation to pass. If you instead require a maximum of 10 digits, but fewer digits than this also acceptable, then you could use ^[0-9]{1,10}.
Just use maxlength attribute without directive
<input type="text" class="form-control" ng-model="sample" maxlength="10">
EDIT
Change it to type="number" if you want to have only numbers,
<input type="number" class="form-control" ng-model="sample" maxlength="10">

Numeric only text box in Angular JS

I want to make textbox numeric only in my Angular JS application.
Here is my code-
script.js
app.directive('numbersonly', function () {
return {
restrict: 'A',
link: function (scope, elm, attrs, ctrl) {
elm.on('keydown', function (event) {
if (event.which == 64 || event.which == 16) {
// to allow numbers
return false;
} else if (event.which >= 48 && event.which <= 57) {
// to allow numbers
return true;
} else if (event.which >= 96 && event.which <= 105) {
// to allow numpad number
return true;
} else if ([8, 13, 27, 37, 38, 39, 40].indexOf(event.which) > -1) {
// to allow backspace, enter, escape, arrows
return true;
} else {
event.preventDefault();
// to stop others
return false;
}
});
}
}
});
And on UI-
<input type="text" id="txtEmpAge" data-ng-model="newemployee.Age" class="form-control" numbersonly required />
But the text box is accepting both numeric and character.
If it is not necessary to use your own implementation, try Angular's number type input.
You can use type=number
<input type="number" id="txtEmpAge" data-ng-model="newemployee.Age" class="form-control" required />
This will take only number values in the text box.
in my opinion, best way to achieve
, it will also not allow user to copy paste strings to input
<input type="number" onkeypress='return event.charCode >= 48 && event.charCode <= 57'></input>
Use the following snippet to make the input field to accept only characters between 0 to 9. This will eliminate the decimal pointer.
<input type="number" onkeypress="return isNumKey(event)"/>
use this function to trigger on key is pressed.
function isNumKey(evt){
var charCode = (evt.which) ? evt.which : event.keyCode
if (charCode > 31 && (charCode < 48 || charCode > 57))
return false;
return true;
}

angularjs : how to restrict input type number to allow only even number with min and max limit as well as steps to increase

I am working on one requirement where I want to allow only even numbers to text box or number box(input type number). with minimum and maximum limit like from 4 to 14 and it should only increase by step of 2 if we have number box.
I tried with HTML input type number with min max and step attributes it's working fine but we can edit the text box with any number so to restrict I tried using directive but it's not working out for me. I will be glad if anyone can help me out with this.
HTML :
<body ng-controller="ctrl">
new : <number-only-input step="2" min="4" max="14" input-value="wks.number" input-name="wks.name" >
</body>
Script :
var app = angular.module('app', []);
app.controller('ctrl', function($scope){
$scope.name = 'Samir Shah';
$scope.price = -10;
$scope.wks = {number: '', name: 'testing'};
});
app.directive('numberOnlyInput', function () {
return {
restrict: 'EA',
template: '<input type="text" name="{{inputName}}" ng-model="inputValue" />',
scope: {
inputValue: '=',
inputName: '=',
min: '#',
max: '#',
step: '#'
},
link: function (scope) {
scope.$watch('inputValue', function(newValue,oldValue) {
var arr = String(newValue).split("");
if (arr.length === 0) return;
if (arr.length === 1 && (arr[0] == '-' || arr[0] === '.' )) return;
if (arr.length === 2 && newValue === '-.') return;
if (isNaN(newValue)) {
scope.inputValue = oldValue;
return;
}
if(!isNaN(newValue)){
if(newValue < parseInt(scope.min) || newValue > parseInt(scope.max)){
scope.inputValue = oldValue;
return;
}
}
});
}
};
});
<form name="testForm">
<div ng-controller="MyCtrl">
<input type="text" name="testInput" ng-model="number" ng-min="2" ng-max="14" required="required" numbers-only="numbers-only" />
<div ng-show="testForm.testInput.$error.nonnumeric" style="color: red;">
Numeric input only.
</div>
<div ng-show="testForm.testInput.$error.belowminimum" style="color: red;">
Number is too small.
</div>
<div ng-show="testForm.testInput.$error.abovemaximum" style="color: red;">
Number is too big.
</div>
<div ng-show="testForm.testInput.$error.odd" style="color: red;">
Numeric is odd.
</div>
</div>
</form>
angular.module('myApp', []).directive('numbersOnly', function () {
return {
require: 'ngModel',
link: function (scope, element, attrs, modelCtrl) {
element.bind('blur', function () {
if (parseInt(element.val(), 10) < attrs.ngMin) {
modelCtrl.$setValidity('belowminimum', false);
scope.$apply(function () {
element.val('');
});
}
});
modelCtrl.$parsers.push(function (inputValue) {
// this next if is necessary for when using ng-required on your input.
// In such cases, when a letter is typed first, this parser will be called
// again, and the 2nd time, the value will be undefined
if (inputValue == undefined) return ''
var transformedInput = inputValue.replace(/[^0-9]/g, '');
if (transformedInput != inputValue || (parseInt(transformedInput, 10) < parseInt(attrs.ngMin, 10) && transformedInput !== '1') || parseInt(transformedInput, 10) > parseInt(attrs.ngMax, 10) || (transformedInput % 2 !== 0 && transformedInput !== '1')) {
if (transformedInput != inputValue) {
modelCtrl.$setValidity('nonnumeric', false);
} else {
modelCtrl.$setValidity('nonnumeric', true);
}
if (parseInt(transformedInput, 10) < parseInt(attrs.ngMin, 10) && transformedInput !== '1') {
modelCtrl.$setValidity('belowminimum', false);
} else {
modelCtrl.$setValidity('belowminimum', true);
}
if (parseInt(transformedInput, 10) > parseInt(attrs.ngMax, 10)) {
modelCtrl.$setValidity('abovemaximum', false);
} else {
modelCtrl.$setValidity('abovemaximum', true);
}
if (transformedInput % 2 !== 0 && transformedInput !== '1') {
modelCtrl.$setValidity('odd', false);
} else {
modelCtrl.$setValidity('odd', true);
}
transformedInput = '';
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
return transformedInput;
}
modelCtrl.$setValidity('nonnumeric', true);
modelCtrl.$setValidity('belowminimum', true);
modelCtrl.$setValidity('abovemaximum', true);
modelCtrl.$setValidity('odd', true);
return transformedInput;
});
}
};
});
Active fiddle http://jsfiddle.net/tuckerjt07/1Ldmkmog/
You could define a property with getter and setter to process the entered value. If the value does not match the requrements display messages but not accept new value.
Using this method you could apply any validation logic, the second field editValue is needed because otherwise you could not enter an invalid number. Therefore editValue alows to enter numbers with numerous digits which will be partially invalid during entering the value.
Property:
// Property used to bind input containing validation
Object.defineProperty($scope, "number", {
get: function() {
return $scope.editValue;
},
set: function(value) {
value = parseInt(value);
$scope.editValue = value;
var isValid = true;
// Min?
if (value < parseInt($scope.min)) {
$scope.toSmall = true;
isValid = false;
} else {
$scope.toSmall = false;
}
// Max?
if (value > parseInt($scope.max)) {
$scope.toBig = true;
isValid = false;
} else {
$scope.toBig = false;
}
// Step not valid
if (value % parseInt($scope.step) > 0) {
$scope.stepNotValid = true;
isValid = false;
} else {
$scope.stepNotValid = false;
}
$scope.isValid = isValid;
if (isValid) {
$scope.value = value;
}
}
});
Working example
Below you can find a complete working example directive containing the property described above including increase/decrease buttons:
var app = angular.module('myApp', []);
app.directive('numberOnlyInput', function() {
return {
restrict: 'E',
template: '<input type="text" ng-model="number" ng-class="{\'error\': !isValid}"/><button ng-click="increase()">+</button><button ng-click="decrease()">-</button> Value: {{value}} {{stepNotValid ? (" value must be in steps of " + step) : ""}} {{toSmall ? " value must be greater or equal to " + min : ""}} {{toBig ? " value must be smaler or equal to " + max : ""}}',
scope: {
value: '=value',
min: '#',
max: '#',
step: '#'
},
link: function($scope) {
// Increase value
$scope.increase = function() {
var newValue = parseInt($scope.value) + parseInt($scope.step);
if (newValue <= $scope.max) {
$scope.number = newValue;
$scope.editValue = $scope.number;
}
};
// Decrease value
$scope.decrease = function() {
var newValue = parseInt($scope.value) - parseInt($scope.step);
if (newValue >= $scope.min) {
$scope.number = newValue;
$scope.editValue = $scope.number;
}
};
// Property used to bind input containing validation
Object.defineProperty($scope, "number", {
get: function() {
return $scope.editValue;
},
set: function(value) {
value = parseInt(value);
$scope.editValue = value;
var isValid = true;
// Min?
if (value < parseInt($scope.min)) {
$scope.toSmall = true;
isValid = false;
} else {
$scope.toSmall = false;
}
// Max?
if (value > parseInt($scope.max)) {
$scope.toBig = true;
isValid = false;
} else {
$scope.toBig = false;
}
// Step not valid
if (value % parseInt($scope.step) > 0) {
$scope.stepNotValid = true;
isValid = false;
} else {
$scope.stepNotValid = false;
}
$scope.isValid = isValid;
if (isValid) {
$scope.value = value;
}
}
});
// Init actual Value of the input element
$scope.number = parseInt($scope.value);
$scope.editValue = parseInt($scope.value);
}
};
});
app.controller('controller', function($scope) {
$scope.value = 10;
});
.error {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="controller">
Number:
<number-only-input min="4" max="14" step="2" value="value"></number-only-input>
</div>
Why are you doing too much of work of a simple thing. Max length will not work with <input type="number" the best way I know is to use oninput event to limit the maxlength. Please see the below code, Its a generic solution work with all the Javascript framework.
<input name="somename"
oninput="javascript: if (this.value.length > this.maxLength) this.value = this.value.slice(0, this.maxLength);"
type = "number"
maxlength = "6"
/>

angularjs move focus to next control on enter

What is the best way, when hitting enter inside a form, the focus to go to the next input instead submitting the form with angularjs.
I have a form with a lot of fields and customers are used to hit enter to move to the next input (comming from desktop applications). The angularjs saves the form when the user hits enter. I like to change this. Is it possible ?
I suggest making a custom directive. Something like this. I haven't tested this.
.directive('focus', function() {
return {
restrict: 'A',
link: function($scope,elem,attrs) {
elem.bind('keydown', function(e) {
var code = e.keyCode || e.which;
if (code === 13) {
e.preventDefault();
elem.next().focus();
}
});
}
}
});
Something like that should work. You might have to tweek something. Good luck.
Create a custom directive:
.directive('nextOnEnter', function () {
return {
restrict: 'A',
link: function ($scope, selem, attrs) {
selem.bind('keydown', function (e) {
var code = e.keyCode || e.which;
if (code === 13) {
e.preventDefault();
var pageElems = document.querySelectorAll('input, select, textarea'),
elem = e.srcElement || e.target,
focusNext = false,
len = pageElems.length;
for (var i = 0; i < len; i++) {
var pe = pageElems[i];
if (focusNext) {
if (pe.style.display !== 'none') {
angular.element(pe).focus();
break;
}
} else if (pe === elem) {
focusNext = true;
}
}
}
});
}
}
})
This is the directive I ended up with (thanks to Zack Argyle):
angular.module('myApp').directive("nextFocus", nextFocus);
/** Usage:
<input next-focus id="field1">
<input next-focus id="field2">
<input id="field3">
Upon pressing ENTER key the directive will switch focus to
the next field id e.g field2
The last field should not have next-focus directive to avoid
focusing on non-existing element.
Works for Web, iOS (Go button) & Android (Next button) browsers,
**/
function nextFocus() {
var directive = {
restrict: 'A',
link: function(scope, elem, attrs) {
elem.bind('keydown', function(e) {
var partsId = attrs.id.match(/field(\d{1})/);
var currentId = parseInt(partsId[1]);
var code = e.keyCode || e.which;
if (code === 13) {
e.preventDefault();
document.querySelector('#field' + (currentId + 1)).focus();
}
});
}
};
return directive;
}
I tried this solution out. As advertised, it needed some tweaking. Here is what ended up working for me:
.directive("focus", function () {
return {
restrict: "A",
link: function ($scope, elem, attrs) {
var focusables = $(":focusable");
elem.bind("keydown", function (e) {
var code = e.keyCode || e.which;
if (code === 13) {
var current = focusables.index(this);
var next = focusables.eq(current + 1).length ? focusables.eq(current + 1) : focusables.eq(0);
next.focus();
e.preventDefault();
}
});
}
}
Note that the in order to get the :focusable pseudo to work, you will need to reference JQueryUI. (the latest version 1.11.4 worked for me)
This is the directive I ended up with (thanks to Zack Argyle and Oleg):
app.directive("nextFocus", function () {
/** Usage:
<input next-focus tabindex="0" id="field1">
<input next-focus tabindex="1" id="field2">
<input id="field3">
Upon pressing ENTER key the directive will switch focus to
the next field id e.g field2
The last field should not have next-focus directive to avoid
focusing on non-existing element.
Works for Web, iOS (Go button) & Android (Next button) browsers,
**/
var directive = {
restrict: 'A',
link: function (scope, elem, attrs) {
elem.bind('keydown', function (e) {
var code = e.keyCode || e.which;
if (code === 13) {
try {
if (attrs.tabindex != undefined) {
var currentTabIndex = attrs.tabindex;
var nextTabIndex = parseInt(attrs.tabindex) + 1;
$("[tabindex=" + nextTabIndex + "]").focus();
}
} catch (e) {
}
}
});
}
};
return directive;
});
Based on the answer by wolcy97 but using only angular
/** Usage:
<input next-focus tabindex="0">
<input next-focus tabindex="1">
<input tabindex="2">
Upon pressing ENTER key the directive will switch focus to
the next tabindex.
The last field should not have next-focus directive to avoid
focusing on non-existing element.
Works for Web, iOS (Go button) & Android (Next button) browsers,
**/
app.directive('nextFocus', [function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
elem.bind('keydown', function(e) {
var code = e.keyCode || e.which;
if (code === 13) {
e.preventDefault();
try {
if (attrs.tabindex !== undefined) {
var currentTabeIndex = attrs.tabindex;
var nextTabIndex = parseInt(currentTabeIndex) + 1;
var elems = document.querySelectorAll("[tabindex]");
for (var i = 0, len = elems.length; i < len; i++) {
var el = angular.element(elems[i]);
var idx = parseInt(el.attr('tabindex'));
if (idx === nextTabIndex) {
elems[i].focus();
break;
}
}
}
} catch (e) {
console.log('Focus error: ' + e);
}
}
});
}
};
}]);
Pure JavaScript Enter as TAB
angular.module('app').directive('tabNext', function () {
return {
restrict: 'A',
link: function (scope, elem) {
elem.bind('keyup', function (e) {
var code = e.keyCode || e.which;
if (code === 13) {
e.preventDefault();
var eIDX = -1;
for (var i = 0; i < this.form.elements.length; i++) {
if (elem.eq(this.form.elements[i])) {
eIDX = i;
break;
}
}
if (eIDX === -1) {
return;
}
var j = eIDX + 1;
var theform = this.form;
while (j !== eIDX) {
if (j >= theform.elements.length){
j = 0;
}
if ((theform.elements[j].type !== "hidden") && (theform.elements[j].type !== "file")
&& (theform.elements[j].name !== theform.elements[eIDX].name)
&& (! theform.elements[j].disabled)
&& (theform.elements[j].tabIndex >= 0)) {
if (theform.elements[j].type === "select-one") {
theform.elements[j].focus();
} else if (theform.elements[j].type === "button") {
theform.elements[j].focus();
} else {
theform.elements[j].focus();
theform.elements[j].select();
}
return;
break;
}
j++;
}
}
});
}
}});
<table class="table table-striped table-bordered table-hover">
<tr>
<th>S No</th>
<th>Stock Id</th>
<th>Description</th>
<th>Qty</th>
<th>UOM</th>
<th>Rate</th>
<th>Amount</th>
<th>Add</th>
<th>Delete</th>
</tr>
<tr ng-repeat="item in stockitems">
<td>{{$index + 1}}</td>
<td>
<input type="text" style="width:70px" id="stkid{{$index}}" class="form-control" name="stockid" required insert="Addnewrow();" ng-keyup="moveFocus('desc','amount','stkid','stkid',$index,$event)" ng-blur="getStockitem($index);" typeahead="a.stockitem_code as (a.stockitem_code +' | ' + a.stockitem_name +' | '+ a.rate) for a in stock | filter:$viewValue | limitTo:8" data-ng-model="item.stockid" rows="3" />
</td>
<td>
<input type="text" class="form-control" id="desc{{$index}}" name="description" ng-keyup="moveFocus('quantity','stkid','desc','desc',$index,$event)" data-ng-model="item.description" rows="3" />
</td>
<td>
<input type="text" style="width:70px" id="quantity{{$index}}" class="form-control" ng-keyup="moveFocus('uom','desc','quantity','quantity',$index,$event)" ng-change="GetAmount($index,'qty');" ng-pattern="/^\d+$/" required name="qty" data-ng-model="item.qty" rows="3" />
</td>
<td>
<input type="text" style="width:70px" id="uom{{$index}}" class="form-control" name="uom" ng-keyup="moveFocus('rate','quantity','uom','uom',$index,$event)" data-ng-model="item.uom" required rows="3" />
</td>
<td>
<input type="text" style="width:70px" id="rate{{$index}}" class="form-control" name="rate" ng-keyup="moveFocus('amount','uom','rate','rate',$index,$event)" required data-ng-model="item.rate" ng-pattern="/^\d{0,9}(\.\d{1,9})?$/" ng-change="GetAmount($index,'rate');" rows="3" />
</td>
<td>
<input type="text" style="width:70px" id="amount{{$index}}" class="form-control" ng-keyup="moveFocus('stkid','rate','amount','amount',$index,$event)" name="amount" required data-ng-model="item.amount" rows="3" />
</td>
<td><span ng-click="AddEstimation($index);"><a>Add</a></span></td>
<td><span ng-click="DeleterowEstimation($index);"><a>Delete</a></span></td>
</tr>
</table>
$scope.moveFocus = function (nextId,prevId,downId,upId,index,event) {
debugger;
if (event.keyCode == 39) {
nextId = nextId + index;
$('#' + nextId).focus();
}
else if(event.keyCode == 37)
{
prevId = prevId + index;
$('#' + prevId).focus();
}
else if(event.keyCode == 38)
{
upId = upId + (index - 1);
$('#' + upId).focus();
}
else if(event.keyCode == 40)
{
downId = downId + (index + 1);
$('#' + downId).focus();
}
else if(event.keyCode==13)
{
if (nextId == "desc") {
nextId = "quantity" + index;
$('#' + nextId).focus();
}
else if(nextId == "uom")
{
nextId = "stkid" + (index + 1);
$('#' + nextId).focus();
}
}
};
On Enter press it moves to next element of DOM, but element requires id to set focus
starter.directive('focustonext', function () {
return {
restrict: 'A',
link: function ($scope, selem, attrs) {
selem.bind('keydown', function (e) {
var code = e.keyCode || e.which;
if (code === 13) {
e.preventDefault();
var pageElems = document.querySelectorAll('input, select, textarea'),
elem = e.srcElement || e.target,
focusNext = false,
len = pageElems.length;
for (var i = 0; i < len; i++) {
var pe = pageElems[i];
if (focusNext) {
if (pe.style.display !== 'none') {
document.getElementById(pe.id).focus();
break;
}
} else if (pe === elem) {
focusNext = true;
}
}
}
});
}
}
});
Thanks all..

Resources