capitalize input with angularjs - keep cursor position - angularjs

I'm working on an application that has a 'inputText', this 'input' I am implementing a policy so that the words are capitalized. However, after having inserted a few words on 'input' I need to edit them and the mouse cursor is moved to the last letter of the last word, how can I fix?
Note: I am using the following directive:
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
var capitalize = function(inputValue) {
if(inputValue == undefined) inputValue = '';
var capitalized = inputValue.toUpperCase();
if(capitalized !== inputValue) {
modelCtrl.$setViewValue(capitalized);
modelCtrl.$render();
}
return capitalized;
};
modelCtrl.$parsers.push(capitalize);
capitalize(scope[attrs.ngModel]); // capitalize initial value
}
};

I think the easiest way to do it, is to store the cursor position before making everything uppercase and then restore the old position afterwards.
The cursor jumps to the end because the complete model/text is replaced in the input field.
Please have a look at the demo below or at this jsfiddle.
angular.module('demoApp', [])
.controller('mainController', function ($scope) {
$scope.text = 'hello world';
})
.directive('capitalize', function () {
return {
require: 'ngModel',
link: function (scope, element, attrs, modelCtrl) {
var caretPos,
capitalize = function (inputValue) {
caretPos = element[0].selectionStart; // save current caret position
//console.log('curPos before change', caretPos);
//if (inputValue == undefined) inputValue = '';
var capitalized = inputValue.toUpperCase();
//console.log(capitalized, inputValue);
if (capitalized !== inputValue) {
modelCtrl.$setViewValue(capitalized);
modelCtrl.$render();
element[0].selectionStart = caretPos; // restore position
element[0].selectionEnd = caretPos;
}
return capitalized;
};
modelCtrl.$parsers.push(capitalize);
capitalize(scope[attrs.ngModel]); // capitalize initial value
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainController">
<input ng-model="text" capitalize=""/>
{{text}}
</div>

Related

angularjs directive - capitalize

I have this code below working fine when a user is typing an input data. But my problem is when the data is from the database(auto filled) my directive is not working(capitalize the letter
). Is there a reason why its not working?.
But when using a class="text-uppercase" its working.
HTML
<input ng-model="profile.Name" type="text" placeholder="" maxlength="40" capitalize />
JS
app.directive('capitalize', function ($parse) {
return {
require: 'ngModel',
link: function (scope, element, attrs, modelCtrl) {
var capitalize = function (inputValue) {
if (inputValue === undefined) { inputValue = ''; }
var capitalized = inputValue.toUpperCase();
//for (var i = 0; i < capitalized.length; i++) {
// capitalized[i] = capitalized[i].charAt(0).toUpperCase() + capitalized[i].substring(1);
//}
if (capitalized !== inputValue) {
modelCtrl.$setViewValue(capitalized);
modelCtrl.$render();
}
return capitalized;
}
modelCtrl.$parsers.push(capitalize);
capitalize($parse(attrs.ngModel)(scope)); // capitalize initial value
}
};
});
You can check below for more information on require: 'ngModel' configure setting.
What's the meaning of require: 'ngModel'?

How to remove zero before valid number in input text field - angularjs

I want to remove or trim zero as first or before the valid number in input text field.
I have a text field and am restricting the user to enter only numbers. When I enter the value as "0145" it should read as "145".
<div ng-controller="MyCtrl">
<input type="text" ng-model="number" required="required" numbers-only="numbers-only" />
</div>
JavaScript:
angular.module('myApp', []).directive('numbersOnly', function(){
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
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) {
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
}
return transformedInput;
});
}
};
});
function MyCtrl($scope) {
$scope.number = ''
}
JSFiddle
Change your regex to:
var transformedInput = inputValue.replace(/^[^1-9]*|[^0-9]/g, '');
Your regex is slightly wrong. It should be:
var transformedInput = inputValue.replace(/^0*/g, '')
This will replace all the 0's at the beginning of the string

How to find when a specific character is typed in textarea

We have requirement to show a drop down when user enters a "#".
I am planning to have a directive as following:
app.controller('MainCtrl', function($scope) {
$scope.values = ['#'];
$scope.valuesEntered = false;
});
app.directive('identifier', function ($parse) {
return {
scope: {
values: '=values'
},
link: function (scope, elm, attrs) {
elm.bind('keypress', function(e){
var char = String.fromCharCode(e.which||e.charCode||e.keyCode), matches = [];
angular.forEach(scope.values, function(value, key){
if(char === value) matches.push(char);
}, matches);
if(matches.length !== 0){
$scope.valuesEntered = true;
}
});
}
}
});
Will this be ok ?
Here is a simple directive I made that will allow you to specify an expression to evaluate when a given key is pressed or one of an array of keys is pressed.
Note that this is a one-way street. There is currently no going back once you have detected that keypress, even if the user pressed backspace.
var app = angular.module('sample', []);
app.controller('mainCtrl', function($scope) {
$scope.values = ['#', '!'];
$scope.valuesEntered = false;
$scope.valuesEntered2 = false;
});
app.directive('whenKeyPressed', function($parse) {
return {
restrict: 'A',
scope: {
action: '&do'
},
link: function(scope, elm, attrs) {
var charCodesToMatch = [];
attrs.$observe('whenKeyPressed', function(keys) {
if (angular.isArray(keys))
charCodesToMatch = keys.map(function(key) {
if (angular.isString(key))
return key.charCodeAt(0);
});
else if (angular.isString(keys))
charCodesToMatch = keys.split('').map(function(ch) {
return ch.charCodeAt(0);
});
});
elm.bind('keypress', function(e) {
var charCode = e.which || e.charCode || e.keyCode;
if (charCodesToMatch.indexOf(charCode) > -1)
scope.action();
});
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="sample">
<div ng-controller="mainCtrl">
<p>Values "#" entered? {{valuesEntered}}</p>
<textarea ng-model="str" when-key-pressed="#" do="valuesEntered = true"></textarea>
<p>Values {{values}} entered 2: {{valuesEntered2}}</p>
<textarea ng-model="str2" when-key-pressed="{{values}}" do="valuesEntered2 = true"></textarea>
</div>
</div>
Plunkr demo

How to allow only a number (digits and decimal point) to be typed in an input?

What is the way to allow only a valid number typed into a textbox?
For example, user can type in "1.25", but cannot type in "1.a" or "1..". When user try to type in the next character which will make it an invalid number, they cannot type it in.
I wrote a working CodePen example to demonstrate a great way of filtering numeric user input. The directive currently only allows positive integers, but the regex can easily be updated to support any desired numeric format.
My directive is easy to use:
<input type="text" ng-model="employee.age" valid-number />
The directive is very easy to understand:
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope) {
});
app.directive('validNumber', function() {
return {
require: '?ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
if(!ngModelCtrl) {
return;
}
ngModelCtrl.$parsers.push(function(val) {
if (angular.isUndefined(val)) {
var val = '';
}
var clean = val.replace( /[^0-9]+/g, '');
if (val !== clean) {
ngModelCtrl.$setViewValue(clean);
ngModelCtrl.$render();
}
return clean;
});
element.bind('keypress', function(event) {
if(event.keyCode === 32) {
event.preventDefault();
}
});
}
};
});
I want to emphasize that keeping model references out of the directive is important.
I hope you find this helpful.
Big thanks to Sean Christe and Chris Grimes for introducing me to the ngModelController
You could try this directive to stop any invalid characters from being entered into an input field. (Update: this relies on the directive having explicit knowledge of the model, which is not ideal for reusability, see below for a re-usable example)
app.directive('isNumber', function () {
return {
require: 'ngModel',
link: function (scope) {
scope.$watch('wks.number', 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.wks.number = oldValue;
}
});
}
};
});
It also accounts for these scenarios:
Going from a non-empty valid string to an empty string
Negative values
Negative decimal values
I have created a jsFiddle here so you can see how it works.
UPDATE
Following Adam Thomas' feedback regarding not including model references directly inside a directive (which I also believe is the best approach) I have updated my jsFiddle to provide a method which does not rely on this.
The directive makes use of bi-directional binding of local scope to parent scope. The changes made to variables inside the directive will be reflected in the parent scope, and vice versa.
HTML:
<form ng-app="myapp" name="myform" novalidate>
<div ng-controller="Ctrl">
<number-only-input input-value="wks.number" input-name="wks.name"/>
</div>
</form>
Angular code:
var app = angular.module('myapp', []);
app.controller('Ctrl', function($scope) {
$scope.wks = {number: 1, name: 'testing'};
});
app.directive('numberOnlyInput', function () {
return {
restrict: 'EA',
template: '<input name="{{inputName}}" ng-model="inputValue" />',
scope: {
inputValue: '=',
inputName: '='
},
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;
}
});
}
};
});
First of all Big thanks to Adam thomas
I used the same Adam's logic for this with a small modification to accept the decimal values.
Note: This will allow digits with only 2 decimal values
Here is my Working Example
HTML
<input type="text" ng-model="salary" valid-number />
Javascript
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope) {
});
app.directive('validNumber', function() {
return {
require: '?ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
if(!ngModelCtrl) {
return;
}
ngModelCtrl.$parsers.push(function(val) {
if (angular.isUndefined(val)) {
var val = '';
}
var clean = val.replace(/[^0-9\.]/g, '');
var decimalCheck = clean.split('.');
if(!angular.isUndefined(decimalCheck[1])) {
decimalCheck[1] = decimalCheck[1].slice(0,2);
clean =decimalCheck[0] + '.' + decimalCheck[1];
}
if (val !== clean) {
ngModelCtrl.$setViewValue(clean);
ngModelCtrl.$render();
}
return clean;
});
element.bind('keypress', function(event) {
if(event.keyCode === 32) {
event.preventDefault();
}
});
}
};
});
Use the step tag to set the minimum changeable value to some decimal number:
e.g.
step="0.01"
<input type="number" step="0.01" min="0" class="form-control"
name="form_name" id="your_id" placeholder="Please Input a decimal number" required>
There is some documentation on it here:
http://blog.isotoma.com/2012/03/html5-input-typenumber-and-decimalsfloats-in-chrome/
DEMO - - jsFiddle
Directive
.directive('onlyNum', function() {
return function(scope, element, attrs) {
var keyCode = [8,9,37,39,48,49,50,51,52,53,54,55,56,57,96,97,98,99,100,101,102,103,104,105,110];
element.bind("keydown", function(event) {
console.log($.inArray(event.which,keyCode));
if($.inArray(event.which,keyCode) == -1) {
scope.$apply(function(){
scope.$eval(attrs.onlyNum);
event.preventDefault();
});
event.preventDefault();
}
});
};
});
HTML
<input type="number" only-num>
Note : Do not forget include jQuery with angular js
You could easily use the ng-pattern.
ng-pattern="/^[1-9][0-9]{0,2}(?:,?[0-9]{3}){0,3}(?:\.[0-9]{1,2})?$/"
There is an input number directive which I belive can do just what you want.
<input type="number"
ng-model="{string}"
[name="{string}"]
[min="{string}"]
[max="{string}"]
[required]
[ng-required="{string}"]
[ng-minlength="{number}"]
[ng-maxlength="{number}"]
[ng-pattern="{string}"]
[ng-change="{string}"]>
the official doc is here: http://docs.angularjs.org/api/ng.directive:input.number
HTML
<input type="text" name="number" only-digits>
// Just type 123
.directive('onlyDigits', function () {
return {
require: 'ngModel',
restrict: 'A',
link: function (scope, element, attr, ctrl) {
function inputValue(val) {
if (val) {
var digits = val.replace(/[^0-9]/g, '');
if (digits !== val) {
ctrl.$setViewValue(digits);
ctrl.$render();
}
return parseInt(digits,10);
}
return undefined;
}
ctrl.$parsers.push(inputValue);
}
};
// type: 123 or 123.45
.directive('onlyDigits', function () {
return {
require: 'ngModel',
restrict: 'A',
link: function (scope, element, attr, ctrl) {
function inputValue(val) {
if (val) {
var digits = val.replace(/[^0-9.]/g, '');
if (digits !== val) {
ctrl.$setViewValue(digits);
ctrl.$render();
}
return parseFloat(digits);
}
return undefined;
}
ctrl.$parsers.push(inputValue);
}
};
I wanted a directive that could be limited in range by min and max attributes like so:
<input type="text" integer min="1" max="10" />
so I wrote the following:
.directive('integer', function() {
return {
restrict: 'A',
require: '?ngModel',
link: function(scope, elem, attr, ngModel) {
if (!ngModel)
return;
function isValid(val) {
if (val === "")
return true;
var asInt = parseInt(val, 10);
if (asInt === NaN || asInt.toString() !== val) {
return false;
}
var min = parseInt(attr.min);
if (min !== NaN && asInt < min) {
return false;
}
var max = parseInt(attr.max);
if (max !== NaN && max < asInt) {
return false;
}
return true;
}
var prev = scope.$eval(attr.ngModel);
ngModel.$parsers.push(function (val) {
// short-circuit infinite loop
if (val === prev)
return val;
if (!isValid(val)) {
ngModel.$setViewValue(prev);
ngModel.$render();
return prev;
}
prev = val;
return val;
});
}
};
});
Here's my really quick-n-dirty one:
<!-- HTML file -->
<html ng-app="num">
<head></head>
<body ng-controller="numCtrl">
<form class="digits" name="digits" ng-submit="getGrades()" novalidate >
<input type="text" placeholder="digits here plz" name="nums" ng-model="nums" required ng-pattern="/^(\d)+$/" />
<p class="alert" ng-show="digits.nums.$error.pattern">Numbers only, please.</p>
<br>
<input type="text" placeholder="txt here plz" name="alpha" ng-model="alpha" required ng-pattern="/^(\D)+$/" />
<p class="alert" ng-show="digits.alpha.$error.pattern">Text only, please.</p>
<br>
<input class="btn" type="submit" value="Do it!" ng-disabled="!digits.$valid" />
</form>
</body>
</html>
// Javascript file
var app = angular.module('num', ['ngResource']);
app.controller('numCtrl', function($scope, $http){
$scope.digits = {};
});
This requires you include the angular-resource library for persistent bindings to the fields for validation purposes.
Working example here
Works like a champ in 1.2.0-rc.3+. Modify the regex and you should be all set. Perhaps something like /^(\d|\.)+$/ ? As always, validate server-side when you're done.
This one seems the easiest to me:
http://jsfiddle.net/thomporter/DwKZh/
(Code is not mine, I accidentally stumbled upon it)
angular.module('myApp', []).directive('numbersOnly', function(){
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
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) {
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
}
return transformedInput;
});
}
};
});
I modified Alan's answer above to restrict the number to the specified min/max. If you enter a number outside the range, it will set the min or max value after 1500ms. If you clear the field completely, it will not set anything.
HTML:
<input type="text" ng-model="employee.age" min="18" max="99" valid-number />
Javascript:
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope) {});
app.directive('validNumber', function($timeout) {
return {
require: '?ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
if (!ngModelCtrl) {
return;
}
var min = +attrs.min;
var max = +attrs.max;
var lastValue = null;
var lastTimeout = null;
var delay = 1500;
ngModelCtrl.$parsers.push(function(val) {
if (angular.isUndefined(val)) {
val = '';
}
if (lastTimeout) {
$timeout.cancel(lastTimeout);
}
if (!lastValue) {
lastValue = ngModelCtrl.$modelValue;
}
if (val.length) {
var value = +val;
var cleaned = val.replace( /[^0-9]+/g, '');
// This has no non-numeric characters
if (val.length === cleaned.length) {
var clean = +cleaned;
if (clean < min) {
clean = min;
} else if (clean > max) {
clean = max;
}
if (value !== clean || value !== lastValue) {
lastTimeout = $timeout(function () {
lastValue = clean;
ngModelCtrl.$setViewValue(clean);
ngModelCtrl.$render();
}, delay);
}
// This has non-numeric characters, filter them out
} else {
ngModelCtrl.$setViewValue(lastValue);
ngModelCtrl.$render();
}
}
return lastValue;
});
element.bind('keypress', function(event) {
if (event.keyCode === 32) {
event.preventDefault();
}
});
element.on('$destroy', function () {
element.unbind('keypress');
});
}
};
});
I had a similar problem and update the input[type="number"] example on angular docs for works with decimals precision and I'm using this approach to solve it.
PS: A quick reminder is that the browsers supports the characters 'e' and 'E' in the input[type="number"], because that the keypress event is required.
angular.module('numfmt-error-module', [])
.directive('numbersOnly', function() {
return {
require: 'ngModel',
scope: {
precision: '#'
},
link: function(scope, element, attrs, modelCtrl) {
var currencyDigitPrecision = scope.precision;
var currencyDigitLengthIsInvalid = function(inputValue) {
return countDecimalLength(inputValue) > currencyDigitPrecision;
};
var parseNumber = function(inputValue) {
if (!inputValue) return null;
inputValue.toString().match(/-?(\d+|\d+.\d+|.\d+)([eE][-+]?\d+)?/g).join('');
var precisionNumber = Math.round(inputValue.toString() * 100) % 100;
if (!!currencyDigitPrecision && currencyDigitLengthIsInvalid(inputValue)) {
inputValue = inputValue.toFixed(currencyDigitPrecision);
modelCtrl.$viewValue = inputValue;
}
return inputValue;
};
var countDecimalLength = function (number) {
var str = '' + number;
var index = str.indexOf('.');
if (index >= 0) {
return str.length - index - 1;
} else {
return 0;
}
};
element.on('keypress', function(evt) {
var charCode, isACommaEventKeycode, isADotEventKeycode, isANumberEventKeycode;
charCode = String.fromCharCode(evt.which || event.keyCode);
isANumberEventKeycode = '0123456789'.indexOf(charCode) !== -1;
isACommaEventKeycode = charCode === ',';
isADotEventKeycode = charCode === '.';
var forceRenderComponent = false;
if (modelCtrl.$viewValue != null && !!currencyDigitPrecision) {
forceRenderComponent = currencyDigitLengthIsInvalid(modelCtrl.$viewValue);
}
var isAnAcceptedCase = isANumberEventKeycode || isACommaEventKeycode || isADotEventKeycode;
if (!isAnAcceptedCase) {
evt.preventDefault();
}
if (forceRenderComponent) {
modelCtrl.$render(modelCtrl.$viewValue);
}
return isAnAcceptedCase;
});
modelCtrl.$render = function(inputValue) {
return element.val(parseNumber(inputValue));
};
modelCtrl.$parsers.push(function(inputValue) {
if (!inputValue) {
return inputValue;
}
var transformedInput;
modelCtrl.$setValidity('number', true);
transformedInput = parseNumber(inputValue);
if (transformedInput !== inputValue) {
modelCtrl.$viewValue = transformedInput;
modelCtrl.$commitViewValue();
modelCtrl.$render(transformedInput);
}
return transformedInput;
});
}
};
});
And in your html you can use this approach
<input
type="number"
numbers-only
precision="2"
ng-model="model.value"
step="0.10" />
Here is the plunker with this snippet
Expanding from gordy's answer:
Good job btw. But it also allowed + in the front. This will remove it.
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;
}
if (arr.length > 0) {
if (arr[0] === "+") {
scope.inputValue = oldValue;
}
}
});
Here is a derivative that will also block the decimal point to be entered twice
HTML
<input tabindex="1" type="text" placeholder="" name="salary" id="salary" data-ng-model="salary" numbers-only="numbers-only" required="required">
Angular
var app = angular.module("myApp", []);
app.directive('numbersOnly', function() {
return {
require : 'ngModel', link : function(scope, element, attrs, modelCtrl) {
modelCtrl.$parsers.push(function(inputValue) {
if (inputValue == undefined) {
return ''; //If value is required
}
// Regular expression for everything but [.] and [1 - 10] (Replace all)
var transformedInput = inputValue.replace(/[a-z!##$%^&*()_+\-=\[\]{};':"\\|,<>\/?]/g, '');
// Now to prevent duplicates of decimal point
var arr = transformedInput.split('');
count = 0; //decimal counter
for ( var i = 0; i < arr.length; i++) {
if (arr[i] == '.') {
count++; // how many do we have? increment
}
}
// if we have more than 1 decimal point, delete and leave only one at the end
while (count > 1) {
for ( var i = 0; i < arr.length; i++) {
if (arr[i] == '.') {
arr[i] = '';
count = 0;
break;
}
}
}
// convert the array back to string by relacing the commas
transformedInput = arr.toString().replace(/,/g, '');
if (transformedInput != inputValue) {
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
}
return transformedInput;
});
}
};
});
Extending Adam Thomas answer you can easily make this directive more generic by adding input argument with custom regexp:
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope) {
});
app.directive('validInput', function() {
return {
require: '?ngModel',
scope: {
"inputPattern": '#'
},
link: function(scope, element, attrs, ngModelCtrl) {
var regexp = null;
if (scope.inputPattern !== undefined) {
regexp = new RegExp(scope.inputPattern, "g");
}
if(!ngModelCtrl) {
return;
}
ngModelCtrl.$parsers.push(function(val) {
if (regexp) {
var clean = val.replace(regexp, '');
if (val !== clean) {
ngModelCtrl.$setViewValue(clean);
ngModelCtrl.$render();
}
return clean;
}
else {
return val;
}
});
element.bind('keypress', function(event) {
if(event.keyCode === 32) {
event.preventDefault();
}
});
}
}});
HTML
<input type="text" ng-model="employee.age" valid-input
input-pattern="[^0-9]+" placeholder="Enter an age" />
</label>
Live on CodePen
Please check out my component that will help you to allow only a particular data type. Currently supporting integer, decimal, string and time(HH:MM).
string - String is allowed with optional max length
integer - Integer only allowed with optional max value
decimal - Decimal only allowed with optional decimal points and max value (by default 2 decimal points)
time - 24 hr Time format(HH:MM) only allowed
https://github.com/ksnimmy/txDataType
Hope that helps.
DECIMAL
directive('decimal', function() {
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, element, attr, ctrl) {
function inputValue(val) {
if (val) {
var digits = val.replace(/[^0-9.]/g, '');
if (digits.split('.').length > 2) {
digits = digits.substring(0, digits.length - 1);
}
if (digits !== val) {
ctrl.$setViewValue(digits);
ctrl.$render();
}
return parseFloat(digits);
}
return "";
}
ctrl.$parsers.push(inputValue);
}
};
});
DIGITS
directive('entero', function() {
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, element, attr, ctrl) {
function inputValue(val) {
if (val) {
var value = val + ''; //convert to string
var digits = value.replace(/[^0-9]/g, '');
if (digits !== value) {
ctrl.$setViewValue(digits);
ctrl.$render();
}
return parseInt(digits);
}
return "";
}
ctrl.$parsers.push(inputValue);
}
};
});
angular directives for validate numbers

How to autocapitalize the first character in an input field in AngularJS?

How to autocapitalize the first character in an input field inside an AngularJS form element?
I saw the jQuery solution already, but believe this has to be done differently in AngularJS by using a directive.
Yes, you need to define a directive and define your own parser function:
myApp.directive('capitalizeFirst', function($parse) {
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
var capitalize = function(inputValue) {
if (inputValue === undefined) { inputValue = ''; }
var capitalized = inputValue.charAt(0).toUpperCase() +
inputValue.substring(1);
if(capitalized !== inputValue) {
modelCtrl.$setViewValue(capitalized);
modelCtrl.$render();
}
return capitalized;
}
modelCtrl.$parsers.push(capitalize);
capitalize($parse(attrs.ngModel)(scope)); // capitalize initial value
}
};
});
HTML:
<input type="text" ng-model="obj.name" capitalize-first>
Fiddle
Please remember that not everything needs an Angular solution. You see this a lot with the jQuery crowd; they like to use expensive jQuery functions to do things that are simpler or easier to do with pure javascript.
So while you might very well need a capitalize function and the above answers provide that, it's going to be a lot more efficient to just use the css rule "text-transform: capitalize"
<tr ng-repeat="(key, value) in item">
<td style="text-transform: capitalize">{{key}}</td>
<td>{{item}}</td>
</tr>
You can create a custom filter 'capitalize' and apply it to any string you want:
<div ng-controller="MyCtrl">
{{aString | capitalize}} !
</div>
JavaScript code for filter:
var app = angular.module('myApp',[]);
myApp.filter('capitalize', function() {
return function(input, scope) {
return input.substring(0,1).toUpperCase()+input.substring(1);
}
});
Use the CSS :first-letter pseudo class.
You need to put everything lowercase and after apply the uppercase only to the first letter
p{
text-transform: lowercase;
}
p:first-letter{
text-transform: uppercase;
}
Here's an example: http://jsfiddle.net/AlexCode/xu24h/
Modified his code to capitalize every first character of word. If you give 'john doe', output is 'John Doe'
myApp.directive('capitalizeFirst', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
var capitalize = function(inputValue) {
var capitalized = inputValue.split(' ').reduce(function(prevValue, word){
return prevValue + word.substring(0, 1).toUpperCase() + word.substring(1) + ' ';
}, '');
if(capitalized !== inputValue) {
modelCtrl.$setViewValue(capitalized);
modelCtrl.$render();
}
return capitalized;
}
modelCtrl.$parsers.push(capitalize);
capitalize(scope[attrs.ngModel]); // capitalize initial value
}
};
});
I would prefer a filter and directive. This should work with cursor movement:
app.filter('capitalizeFirst', function () {
return function (input, scope) {
var text = input.substring(0, 1).toUpperCase() + input.substring(1).toLowerCase();
return text;
}
});
app.directive('capitalizeFirst', ['$filter', function ($filter) {
return {
require: 'ngModel',
link: function (scope, element, attrs, controller) {
controller.$parsers.push(function (value) {
var transformedInput = $filter('capitalizeFirst')(value);
if (transformedInput !== value) {
var el = element[0];
el.setSelectionRange(el.selectionStart, el.selectionEnd);
controller.$setViewValue(transformedInput);
controller.$render();
}
return transformedInput;
});
}
};
}]);
Here is a fiddle
To fix the cursor problem (from where Mark Rajcok's solution),
you can store element[0].selectionStart at the beginning of your method,
and then ensure to reset element[0].selectionStart and element[0].selectionEnd to the stored value before the return.
This should capture your selection range in angular
Generate directive:
ng g directive capitalizeFirst
Update file capitalize-first.directive.ts:
import {Directive, ElementRef, HostListener} from '#angular/core';
#Directive({
selector: '[appCapitalizeFirst]'
})
export class CapitalizeFirstDirective {
constructor(private ref: ElementRef) {
}
#HostListener('input', ['$event'])
onInput(event: any): void {
if (event.target.value.length === 1) {
const inputValue = event.target.value;
this.ref.nativeElement.value = inputValue.charAt(0).toUpperCase() + inputValue.substring(1);
}
}
}
Usage:
<input appCapitalizeFirst>
This code woks with Angular 11+
Comment to Mark Rajcok solution: when using $setViewValue, you trigger the parsers and validators again. If you add a console.log statement at the beginning of your capitalize function, you'll see it printed twice.
I propose the following directive solution (where ngModel is optional):
.directive('capitalize', function() {
return {
restrict: 'A',
require: '?ngModel',
link: function(scope, element, attrs, ngModel) {
var capitalize = function (inputValue) {
return (inputValue || '').toUpperCase();
}
if(ngModel) {
ngModel.$formatters.push(capitalize);
ngModel._$setViewValue = ngModel.$setViewValue;
ngModel.$setViewValue = function(val){
ngModel._$setViewValue(capitalize(val));
ngModel.$render();
};
}else {
element.val(capitalize(element.val()));
element.on("keypress keyup", function(){
scope.$evalAsync(function(){
element.val(capitalize(element.val()));
});
});
}
}
};
});
Here's a codepen for a filter that capitalizes the first letter:
http://codepen.io/WinterJoey/pen/sfFaK
angular.module('CustomFilter', []).
filter('capitalize', function() {
return function(input, all) {
return (!!input) ? input.replace(/([^\W_]+[^\s-]*) */g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}) : '';
}
});
Further to the CSS-only answers, you could always use Twitter Bootstrap:
<td class="text-capitalize">
Building off Mark Rajcok's solution; It's important to consider that the directive evaluate only when the input field in engaged, otherwise you'll get error messages firing off until the input field has a 1st character.
Easy fix with a few conditionals:
A jsfiddle to go with that: https://jsfiddle.net/Ely_Liberov/Lze14z4g/2/
.directive('capitalizeFirst', function(uppercaseFilter, $parse) {
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
var capitalize = function(inputValue) {
if (inputValue != null) {
var capitalized = inputValue.charAt(0).toUpperCase() +
inputValue.substring(1);
if (capitalized !== inputValue) {
modelCtrl.$setViewValue(capitalized);
modelCtrl.$render();
}
return capitalized;
}
};
var model = $parse(attrs.ngModel);
modelCtrl.$parsers.push(capitalize);
capitalize(model(scope));
}
};
});
The problem with css-ony answers is that the angular model is not updated with the view. This is because css only applies styling after rendering.
The following directive updates the model AND remembers the cursors location
app.module.directive('myCapitalize', [ function () {
'use strict';
return {
require: 'ngModel',
restrict: "A",
link: function (scope, elem, attrs, modelCtrl) {
/* Watch the model value using a function */
scope.$watch(function () {
return modelCtrl.$modelValue;
}, function (value) {
/**
* Skip capitalize when:
* - the value is not defined.
* - the value is already capitalized.
*/
if (!isDefined(value) || isUpperCase(value)) {
return;
}
/* Save selection position */
var start = elem[0].selectionStart;
var end = elem[0].selectionEnd;
/* uppercase the value */
value = value.toUpperCase();
/* set the new value in the modelControl */
modelCtrl.$setViewValue(value);
/* update the view */
modelCtrl.$render();
/* Reset the position of the cursor */
elem[0].setSelectionRange(start, end);
});
/**
* Check if the string is defined, not null (in case of java object usage) and has a length.
* #param str {string} The string to check
* #return {boolean} <code>true</code> when the string is defined
*/
function isDefined(str) {
return angular.isDefined(str) && str !== null && str.length > 0;
}
/**
* Check if a string is upper case
* #param str {string} The string to check
* #return {boolean} <code>true</code> when the string is upper case
*/
function isUpperCase(str) {
return str === str.toUpperCase();
}
}
};
}]);
You can use the provided uppercase filter.
http://docs.angularjs.org/api/ng.filter:uppercase
You could use pure css:
input {
text-transform: capitalize;
}

Resources