Angular material input number change format - javascript

In my angular-material app I have a field with validation:
<input type="number" ng-model="myValue"
name="myValue"
min="0" max="100"
ng-pattern="/^[0-9]\d*(\.\d+)?$/" required>
It works fine. But now I need to make it to allow user to type .75 and get instead of 0.75
So the question how to apply my filter:
if( myValue.substring(0,1) == "." ){
myValue = "0" + myValue;
}
before angular material ng-pattern and type="number" validation

You can write some directive with $filter, $formatters and $parsers:
app.directive('parser', ['$filter',
function($filter) {
return {
restrict:'A',
require: 'ngModel',
link: function(scope, element, attrs, ctrl) {
ctrl.$formatters.unshift(function (a) {
return $filter('myFilter')(ctrl.$modelValue)
});
ctrl.$parsers.unshift(function (viewValue) {
element[0].value = $filter('myFilter')(element[0].value);
return element[0].value;
});
}
};
}
]);
app.filter('myFilter', [
function() {
return function(input) {
if( input && input.substring(0,1) == "." ){
input = "0" + input;
}
return input;
};
}
]);
DEMO Plunkr
However you cannot use type number because as I remember . not supported and doesn't parses as integer
Hope it will give you direction

Related

Directive to accept numbers greater than 0 and less than 100

I am trying to create an angular Directive which returns an error when the input of the textfield is less than 5 and greater than 200 i am trying with this code and for some reason it isnt working any help would be appreciated.
JS
app.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, '');
console.log("inputValue"+inputValue);
if(parseInt(inputValue) > 200 || parseInt(inputValue) < 5){
return '';
}
if (transformedInput!=inputValue) {
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
}
return transformedInput;
});
}
};
});
HTML
<div ng-controller="MyCtrl">
<input type="text" ng-model="number" required="required" numbers-only="numbers-only" />
</div>
The plunker that i created is this (http://plnkr.co/edit/QKifStiFmHBF8GhcH3Ds?p=preview)
Any help would be appreciated!
I have given a directive that takes care of your model value to always contain int values between 5 and 200. A 'ng-invalid' class will be added when you do setValidity to false. Using that you can use css to display error to the user. In case you want your input to be updated with the correct model value in case of error, you can do it in the blur event.
app.directive('numbersOnly', function(){
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
modelCtrl.$parsers.push(function (inputValue) {
if(parseInt(inputValue) <= 200 && parseInt(inputValue) >= 5){
modelCtrl.$setValidity('numbersOnly', true);
return inputValue;
} else {
modelCtrl.$setValidity('numbersOnly', false);
return modelCtrl.$modelValue;
}
});
}
};
});
angular already has perfect directives for that. all you need is a form and use Min Max inside input tag
<form name="ue.form">
<input type="number" ng-model="ue.num" name="num" min="5" max="200" >
</form>
<p ng-if="ue.form.$error">
number must be less than 200 and greater than 5
</p>
or you can handle each error separately:
<p ng-if="ue.form.num.$error.min">
number must be greater than 5
</p>
<p ng-if="ue.form.num.$error.max">
number must be less than 200
</p>
if number is not in range 5-200 then form validotor throw an error.
min and max work only with input type="number".
https://plnkr.co/edit/?p=preview
Here's what I would suggest:
Use ng-model-options="{ updateOn: 'blur' }" so that model gets updated only on blur.
Try this code in directive:
app.directive('numbersOnly', function(){
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, element, attrs, ngModel) {
element.on('blur', function() {
if (ngModel.$viewValue < 5 || ngModel.$viewValue > 200) {
ngModel.$setViewValue('');
element.val('');
}
});
}
};
});
You can use ng-messages for these kind of validation purposes
We always can customize ng-messages with our needs.
you can create two directives for min and max. In your case your minimum value is 5 and max is 200, we dont need to hardcode our values inside the directives.
You dont need to worry for adding error messages in your directive. ng-messages will do it for you. You just need to put your messages inside ng-messages div.
Directive
module.directive("min", function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, element, attributes, ngModel) {
ngModel.$validators.min = function (modelValue) {
if (!isNaN(modelValue) && modelValue !== "" && attributes.min !== "")
return parseFloat(modelValue) >= attributes.min;
else
return true;
}
}
};
});
module.directive("max", function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, element, attributes, ngModel) {
ngModel.$validators.max = function (modelValue) {
if (!isNaN(modelValue) && modelValue !== "" && attributes.max !== "")
return parseFloat(modelValue) <= attributes.max;
else
return true;
}
}
};
});
Usage
<form name="myform">
<input type="text" name="minmax" ng-model="number" required="required" min="5" max="200"/>
<div data-ng-messages="myform.minmax.$error" class="error-messages">
<div data-ng-message="min">YOu cant enter below 5</div>
<div data-ng-message="max">You cant enter above 200</div>
</div>
</form>
Here is my pluker example

Number only input in angular js

Number only input:
HTML
<input type="text" ng-model="employee.age" valid-input
input-pattern="[^0-9]+" placeholder="Enter an age" />
</label>
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();
}
});
}
}});
Why the above angularjs code so complicated? To have a number only text input can be done with normal javascript using regular expressions.
I wonder why such a lengthy code for angularjs being so famous?
Can't it be simpler than this?
Try the below approach, hope it works including the trim of white spaces,
<input type="text" ng-model="employee.age"
ng-pattern="^\d+$/|/[^\s*]/" placeholder="Enter an age" />

Input allow only 6 digits and after comma seperated and allow another 6 digits in angular js

Hi i am new to angularjs we want to implement a input text box which will allow only six digits and after entering six digits a comma separated will add and enter another six digits . Can you please help me. The sample code we have now is
**html**
<div ng-controller="MyCtrl">
<input type="text" ng-model="number" required="required" numbers-
only="numbers-only" />
</div>
Angular js controller
angular.module('myApp', []).directive('numbersOnly', function(){
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
modelCtrl.$parsers.push(function (inputValue) {
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 = ''
}
fiddler link we found
http://jsfiddle.net/thomporter/DwKZh/
have a look at ui-mask, set the mask as 999999-999999 or you can also use angular-input-mask
Edit your angular directive and bind a key press event to the textbox element. Inside the event check length. If length is 6 add a comma and rebind new value to your text box.
All you got to do is attach a key press event inside the directive link and check for input length and act accordingly. Instead of modifying your code, I pretty much wrote my own. Here is a DEMO
Here is the HTML code:
<div ng-app="myApp" ng-controller="MyCtrl">
<input type="text" ng-model="number" number-only required="required" />
</div>
Here is the modified directive code:
var app = angular.module('myApp', []);
app.controller('MyCtrl', ['$scope', function($scope) {
}])
app.directive('numberOnly', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
// Attach key press event
elem.bind('keypress', function(e) {
// Check if its a number
if (e.which >= 48 && e.which <= 57) {
var ar = scope.number.split(',');
if (ar[ar.length - 1].length >= 6) {
scope.number = scope.number + ',';
}
scope.$apply();
}
else {
e.preventDefault();
}
});
}
}
});

Custom directive for telephone format using angularjs

I am trying to write custom directive for USA telephone number using angularjs and need to preserve the data type of the field as integer.Here is the jsfiddle directive and need help to complete the directive.
If user enters a valid telephone no (exactly 10 numbers ie.1234567890) then input should split into 3 chunks as 123-456-7890 when the user moves to next control.otherewise I should show error message "not a valid number".
<div ng-app="myApp" ng-controller="myCtrl">
<form name="myForm">
<input type="text" ng-model="telephone" phoneformat name="input1" />
<span class="error" ng-show="myForm.input1.$error.telephone">Numbers only!</span>
<span class="error" ng-show="myForm.input1.$error.telephone">Exact 10 Numbers only!</span>
</form>
</div>
var myApp = angular.module("myApp", []);
var myCtrl = myApp.controller("myCtrl",["$scope", function($scope) {
$scope.telephone = "1234567890";
}]);
myApp.directive("phoneformat", function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, element, attr, ngModelCtrl) {
var phoneformat = function () {
}
}
};
});
It looks like you want to leverage the $error property of the form to drive validation. To do this, you will need to call $setValidity in the ngModelCtrl that you have required into your directive:
var myApp = angular.module("myApp", []);
var myCtrl = myApp.controller("myCtrl",["$scope", function($scope) {
$scope.telephone = "1234567890";
}]);
myApp.directive("phoneformat", function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, element, attr, ngModelCtrl) {
//Parsing is performed from angular from view to model (e.g. update input box)
//Sounds like you just want the number without the hyphens, so take them out with replace
var phoneParse = function (value) {
var numbers = value && value.replace(/-/g, "");
if (/^\d{10}$/.test(numbers)) {
return numbers;
}
return undefined;
}
//Formatting is done from view to model (e.g. when you set $scope.telephone)
//Function to insert hyphens if 10 digits were entered.
var phoneFormat = function (value) {
var numbers = value && value.replace(/-/g,"");
var matches = numbers && numbers.match(/^(\d{3})(\d{3})(\d{4})$/);
if (matches) {
return matches[1] + "-" + matches[2] + "-" + matches[3];
}
return undefined;
}
//Add these functions to the formatter and parser pipelines
ngModelCtrl.$parsers.push(phoneParse);
ngModelCtrl.$formatters.push(phoneFormat);
//Since you want to update the error message on blur, call $setValidity on blur
element.bind("blur", function () {
var value = phoneFormat(element.val());
var isValid = !!value;
if (isValid) {
ngModelCtrl.$setViewValue(value);
ngModelCtrl.$render();
}
ngModelCtrl.$setValidity("telephone", isValid);
//call scope.$apply() since blur event happens "outside of angular"
scope.$apply();
});
}
};
});
Working fiddle. This was just a quick way of demonstrating the parser and formatter pipelines that are used in ngModel, along with $setValidity -- which is used to populate the $error field(s).
Update: To use this same phone validation across multiple phones, use form with $error. Notice that each input gets a unique name that is used with myForm (name of form). Both use $error.telephone:
<form name="myForm">
Mobile Phone:
<input type="text" ng-model="mobilephone" phoneformat name="mobilephone" />
<span class="error" ng-show="myForm.mobilephone.$error.telephone">
Exact 10 Numbers only!
</span>
<br />
Home Phone:
<input type="text" ng-model="homephone" phoneformat name="homephone" />
<span class="error" ng-show="myForm.homephone.$error.telephone">
Exact 10 Numbers only!
</span>
</form>
Updated fiddle.
You might want to use http://angular-ui.github.io/ui-utils/ Mask directive.
Working Fiddle: http://jsfiddle.net/HB7LU/6581/
myApp.directive("phoneFormat", function () {
return {
restrict: "A",
link: function (scope, element, attr) {
element.bind('change', function() {
if ( this.value.length === 10 ) {
var number = this.value;
this.value = number.substring(0,3) + '-' + number.substring(3,6) + '-' + number.substring(6,10)
}
else {
document.querySelector('.helpblock').innerHTML = 'error in formatting';
}
});
}
};
});
Iv'e extended your original fiddle. here's the result:
http://jsfiddle.net/10k58awt/
You can find splittedNumber array (contains 3 parts of number) on form submission
js:
var myApp = angular.module("myApp", []);
var myCtrl = myApp.controller("myCtrl", ["$scope", function ($scope) {
$scope.telephone = "1234567890";
$scope.submit = function () {
var splittedNumber = [$scope.telephone.substring(0, 3), $scope.telephone.substring(3, 6), $scope.telephone.substring(6, 10)];
// Do something with splitted number
console.log(splittedNumber);
};
}]);
myApp.directive("phoneformat", function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function (phoneInput) {
phoneInput = phoneInput.trim();
if (phoneInput && phoneInput.length == 10 && !isNaN(phoneInput)) {
ctrl.$setValidity('phoneformat', true);
return phoneInput;
} else {
ctrl.$setValidity('phoneformat', false);
return undefined;
}
});
}
};
});
html:
<div ng-app="myApp" ng-controller="myCtrl">
<form name="myForm" novalidate ng-submit="myForm.$valid && submit()">
<input type="text" ng-model="telephone" phoneformat name="input1" /> <span class="error" ng-show="myForm.input1.$error.phoneformat">Invalid US Phone number!</span>
<div>
<button class="btn btn-primary" type="submit" ng-class="{'disabled': !myForm.$valid}">submit</button>
</div>
</form>
</div>

Angular Data Binding - Input type="number"

I'm having problems binding a number value using AngularJS.
I've put a simplified example on JSFiddle: http://jsfiddle.net/treerock/ZvdXp/
<div ng-controller="MyCont" ng-app>
<input type="number" min="0" max="50" value="{{value}}" ng-model="value" />
<input type="text" value="{{value}}" ng-model="value" />
<input type="range" min="0" max="50" value="{{value}}" ng-model="value" />
{{value}}
</div>
This should be three different types of input fields, and if you update one, then all values should update. That's working except for the number input. e.g. If I type 20 in the first number box, it updates all other instances of value. But if I update the text or range inputs, the number input goes blank.
I was wondering if the issue was with how the number is represented/converted between fields. e.g. the number input is a float and the text input is a string?
You're right, it has to do with string vs number types. I used a $scope.watch statement to fix it: http://jsfiddle.net/ZvdXp/6/
You can also fix this with a directive. I created a directive to force input bound to numeric fields to be numeric.
Html:
myApp.directive('numericbinding', function () {
return {
restrict: 'A',
require: 'ngModel',
scope: {
model: '=ngModel',
},
link: function (scope, element, attrs, ngModelCtrl) {
if (scope.model && typeof scope.model == 'string') {
scope.model = parseInt(scope.model);
}
}
};
});
You can add it to your numeric field like this:
<input data-ng-model="stringnumber" numericbinding type="number"/>
full example: http://jsfiddle.net/tdjager/cMYQ3/1/
I've expanded on Tim's answer to make it correct the data type after the user updates the control value as well.
myApp.directive('numericbinding', function () {
return {
restrict: 'A',
require: 'ngModel',
scope: {
model: '=ngModel',
},
link: function (scope, element, attrs, ngModelCtrl) {
if (scope.model && typeof scope.model == 'string') {
scope.model = parseInt(scope.model);
}
scope.$watch('model', function(val, old) {
if (typeof val == 'string') {
scope.model = parseInt(val);
}
});
}
};
});
If you prefer to save a numeric value in the model, you can use a directive that convert the string generated by the text input and by the range input in a numeric value through the angular parser, like so:
myApp.directive('numericsaving', function () {
return {
restrict: 'A',
require: '?ngModel',
scope: {
model: '=ngModel'
},
link: function (scope, element, attrs, ngModelCtrl) {
if (!ngModelCtrl) {
return;
}
ngModelCtrl.$parsers.push(function (value) {
if (!value || value==='' || isNaN(parseInt(value)) || parseInt(value)!==value) {
value=0;
}
return parseInt(value);
});
}
};
});
In the HTML, leave the number input as is and add the directive in the others inputs this way:
<input type="number" min="0" max="50" value="{{value}}" ng-model="value" />
<input type="range" min="0" max="50" value="{{value}}" ng-model="value" numericsaving/>
<input type="text" value="{{value}}" ng-model="value" numericsaving/>
The angular parser will translate the string input in a numeric value before saving it in model, so the numeric input will automatically work.
Here the complete fiddle.
Moreover, if the user inserts letters or any strange character in the text input, they will not be saved in the model, preventing invalid value in the single source of truth of your application.
Only '+' and '-' character at the begin of the text will be correctly parsed, so even negative value are allowed.
I hope this helps! :)
TypeScript version inspired ainos984, for the sake of posterity
export class ngIntegerDirective implements ng.IDirective {
static directiveKey: string = 'ngInteger';
require: string = 'ngModel';
link = (scope, ele, attr, ctrl: ng.INgModelController) => {
ctrl.$parsers.unshift(function (viewValue) {
let result: number = parseInt(viewValue,10);
if (isNaN(result)) {
result = 0;
}
return result;
});
}
public static Factory(): ng.IDirectiveFactory {
const directive = () => new ngIntegerDirective();
directive.$inject = []; //injecter les dépendances ici
return directive;
}
}

Categories

Resources