Input field number format AngularJS - angularjs

I have the following input field:
<input type="text" class="span2" ng-model="mynumber">
mynumber has the value 0.55 which is loaded on pageload from a rest service. My problem is now, how can I format the number for different languages/countries? For example, in German, the value should be formatted with a comma (,) instead of a period (.). And if the user changes the number the number should be converted to . instead of ,, if I send it back to the rest service.
This should also work for larger numbers like 90,000.00, which should be 90.000,00 in German...
If I use the angular-locale_de-at.js, I can format the number on a normal output with this:
{{mynumber | number}}
but that does not work for an input field.
How can I handle this? The values should be (printed) formatted in the input field.
If I canage the type of the input field to number
<input type="number" class="span2" ng-model="mynumber">
it works in chrome but not in IE or FF. in chrome i get 0,55. but not in other browsers.
any ideas?

I've written the directive you are looking for. See the code on GitHub.
Also see this answer on SO
Using AngularJS directive to format input field while leaving scope variable unchanged
It will probably not work with <input type="number"/>, use <input type="text"/> instead

Mh,
my first idea would be to separate the concerns here. You're having the model mynumber on the one side and the representation on the other side. Those are distinct from my point of view.
So what you can do is to introduce a directive (I once did this for date values in AngularJS 1.1.5, so bit a bit of additional hacking could be necessary):
First we introduce a directive:
<input type="text" class="span2" ng-model="mynumber" number-format>
with the code:
var app = angular.module("your.directives", ['your.filters']);
app.directive("numberFormat", [
'$filter', function(filter) {
return {
replace: false,
restrict: "A",
require: "?ngModel",
link: function(scope, element, attrs, ngModel) {
var numberFormat;
if (!ngModel) {
return;
}
ngModel.$render = function() {
return element.val(ngModel.$viewValue);
};
var numberFilter = filter('myNumberFilter');
return ngModel.$formatters.push(function(value) {
return numberFilter(value);
});
}
};
}
]);
What you need for this, is a working myNumberFilter filter present, which could decide based on the language given (however you determine this) how to format the input value.
EDIT: I noticed, that AngularJS has it's own number filter, so i changed the name called. Let's add our own:
var app = angular.module("your.filters", []);
app.filter("myNumberFilter", ['SiteLanguage',
function(siteLanguage) {
return function(number) {
var language = siteLanguage.getLanguage(); //I assume you have a service that can tell you the current language
switch(language) {
case "de":
// return the variant of number for "de" here
break;
case "fr":
// return the variant of number for "fr" here
break;
default:
// return english variant here.
break;
};
}
]
});
You'll probably need a formatter function for the individual countries (instead of blindly relying on angular locale. And you probably need a service SiteLanguage which will give you the language on the current site.
Hope this helps :)

Related

AngularJS input date french

I wanted to use an input[date] inside a form to enable users to use the modern browsers' support, without using a javascript datepicker.
For the ones who're using not supporting browsers, I'v set ui-mask. Both work together.
I use the french format (dd/mm/YYYY).
<input type="date" ng-model="myDate" ui-mask="99/99/9999">
$scope.myDate = new Date("2016-02-12"); // works
$scope.myDate = "12/02/2016"; // Doesn't...
In an empty form, no problem, Angular accept it.
But with a filled form, Angular expects a date format I don't want : YYYY-mm-dd (javascript date object).
I can't understand why Angular only provides support that format, and not others like french format. Because I want the input[date] to show the french format, not the standard one !
Many modern browsers provides interesting support for dates, I can't understand why Angular waste that.
Or maybe I missed something ?
To achieve your goal need to use momentJs and ngModel $parsers and $formatters. Below some code and JSFiddle example:
In your controller you prepare some string value in french date format:
$scope.myDate= '12/02/2016';
In view you set this value to ngModel attribute of input[type=date] element:
<input class="form-control" type="date" ng-model="myDate">
You need to create new directive, it can be assigned to input element:
.directive('input', function(dateFilter) {
return {
restrict: 'E',
require: '?ngModel',
link: function(scope, element, attrs, ngModel) {
if (
'undefined' !== typeof attrs.type && 'date' === attrs.type && ngModel
) {
ngModel.$formatters.push(function(modelValue) {
return moment(modelValue, "DD/MM/YYYY").toDate();
});
ngModel.$parsers.push(function(viewValue) {
return moment(viewValue).format("DD/MM/YYYY");
});
}
}
}
})
New function in $formatters array modifies your myDate to javascript date object (with moment parser it's pretty simple). New function in $parsers array modifies value of input element back to french formatted date string.
This solution provides two way binding between your myDate and input[type=date] element. :)
Look at JSFiddle exaple

How to format a input type number field with currency

I have been trying to locate examples of how to add commas to a angular input type="number" field. Everything I have seen uses a type="text". the issue is I need to keep the wheel that the number field has.
Is it possible to work around this? I have seen some css hacks that only work with chrome.
I need all browsers to work.
I came across a similar examples for how to add commas to a angular input type="number" field.
try the below example, i have not tried it, but it looks promising
you may use this example to create a directive as per you need
http://blog.krusen.dk/angularjs-decimals-browsers/
This is not the answer to your original question, as I don't know whether you can insert commas and currency symbols into number fields. Instead of keeping it as number field, but try this, maybe it will help:
Allow text, and limit user input to only digits.
<input type="text" ng-model="value" numbers-only/>
Directive:
.directive('numbersOnly', [
function(){ // limit the input field to numbers only, but retain value as string. Note do not use on type=number input field
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
modelCtrl.$parsers.push(function (inputValue) {
var transformedInput = inputValue;
transformedInput = transformedInput.replace(/\D/g,'');
if(transformedInput)
transformedInput = parseInt(transformedInput)+"";
if (transformedInput!=inputValue) {
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
}
return transformedInput;
});
}
};
}
])
http://plnkr.co/edit/zLj34V7v7xICyfGnlg3k?p=preview

AngularJS trims leading zeros in model, while view/input value still remains unchanged?

For an input element with type number, when the number entered has leading zeros like '0000123456', the model is updated to 123456, while the view/input still remains the same 0000123456.
However if I switch from number to text everything works as expected. I would like to have number since it would display numeric keyboard for mobile devices.
<input type="number" ng-model="vm.orderid"/>
{{vm.orderid}}
PLUNKR
As stated by #Steve, I used a custom directive my-decimals which matches the view value with the model when input losses the focus.
<input type="number" my-decimals ng-model="vm.orderid"/>
angular.directive('myDecimals', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
elm.blur(function() {
var val = ctrl.$viewValue;
ctrl.$setViewValue(val * 1);
ctrl.$render();
});
}
}
});
You have to options for this,
use: <input type = "tel">
it has been introduced for this exact purpose. It's one of the new input types in HTML5.
or, <input type="text" pattern="[0-9]">
It Will bring up the numeric keypad on iPhone and the Android phones.You can test this. I am not 100%sure.

Angular doesn't validating date type

I'm trying to use input[date] in my form, but angularjs doesn't validate any date:
<form name="myForm">
{{birthday}} <br/>
<input type="date" ng-model="birthday" id="birthday" name="birthday"></input>
</form>
If I try to put "alex" inside the input, it accepts!
JSFiddle: http://jsfiddle.net/3GKeM/2/ (please try with firefox)
You're trying to use a new feature in AngularJS 1.3.x from AngularJS 1.0 which doesn't support type="date".
If you want that support on FireFox. You'll have to use AngularJS. 1.3
The documentation you're referring to is for 1.3
https://docs.angularjs.org/api/ng/input/input%5Bdate%5D
This behaves as expected in Firefox. CanIUse.com reports that this HTML5 feature is not yet supported in Firefox 32 or earlier.
So you'll need to implement a javascript solution if you want all browsers to behave similarly. I'd suggest jQuery UI Datepicker. It's used by a lot of people, has an alright look to it (which you can customize actually) and there are lots of examples on how to use it.
Other options:
Pickdate
Bootstrap Datepicker
And the Angular UI Bootstrap option
Update
You stated that you already have your own datepicker (in comments below), and you are just looking for validation: you may want to consider looking at HTML5 Patterns - Date. They have a variety of Regex solutions for validation. They have several different date formats already in place for you.
And then you can use Angular ng-patter to pass in the regex:
example:
<input type="text" ng-pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])"></input>
//accepts: YYYY-MM-DD
I would either use ng-validate and a regex to check the format of the input value or because i do believe ng-validate has been deprecated depending on what version you're using, I would use ng-change on the input where you pass the model for the form to a function where you then check the format of the value and set the model to be invalid or valid. Here's a working example I've pulled from my app where i check to see if it is in fact a phone number and that it begins with 1.
checkNumber: function(number,form) {
var num = parseInt(number.replace(/[^0-9\.]+/g, '')),
l = num.toString().length,
first = num.toString()[0];
console.log(num);
if(number && first != '1' || number && l < 11) {
form.$setValidity('phoneNumber',false);
form.phoneNumber.$setValidity('format',false);
} else {
form.$setValidity('phoneNumber',true);
form.phoneNumber.$setValidity('format',true);
}
}
There are browser inconsistencies as to what constitutes a valid date. A valid date string in firefox or ie, is invalid in chrome and vice-versa. I solved a similar issue by creating a custom validation directive that works quite nicely. you can find it here:
http://jsfiddle.net/fortesl/2uv6xmjL/6/
Also shown below:
app.directive('dateFieldValidator', [function () {
var validateDate = function (date, format) {
if (!date.length) {
return true;
}
return moment(date, format.toUpperCase(), true).isValid();
};
return {
restrict: 'A',
require: 'ngModel',
scope: {
dateFormat: '#'
},
link: function (scope, elem, attrs, ngModelCtrl) {
//For DOM -> model validation
ngModelCtrl.$parsers.unshift(function (value) {
var valid = validateDate(value, scope.dateFormat);
ngModelCtrl.$setValidity('validDate', valid);
return valid ? value : undefined;
});
//For Model Update --> DOM
ngModelCtrl.$formatters.unshift(function (value) {
var valid = validateDate(value, scope.dateFormat);
ngModelCtrl.$setValidity('validDate', valid);
return value;
});
}
};
}]);

ngModel Formatters and Parsers

I posted the same question in different form, but no one answered. I am not getting a clear picture of what the Formatters and Parsers do in angular js.
By the definition, both the Formatters and Parsers look similar to me. Maybe I am wrong, as I am new to this angularjs.
Formatters Definition
Array of functions to execute, as a pipeline, whenever the model value changes.
Each function is called, in turn, passing the value through to the next.
Used to format / convert values for display in the control and validation.
Parsers Definition
Array of functions to execute, as a pipeline, whenever the control reads value from the DOM.
Each function is called, in turn, passing the value through to the next.
Used to sanitize / convert the value as well as validation.
For validation, the parsers should update the validity state using $setValidity(), and return undefined for invalid values.
Please help me to understand both features with a simple example. A simple illustration of both will be appreciated.
This topic was covered really well in a related question: How to do two-way filtering in AngularJS?
To summarize:
Formatters change how model values will appear in the view.
Parsers change how view values will be saved in the model.
Here is a simple example, building on an example in the NgModelController api documentation:
//format text going to user (model to view)
ngModel.$formatters.push(function(value) {
return value.toUpperCase();
});
//format text from the user (view to model)
ngModel.$parsers.push(function(value) {
return value.toLowerCase();
});
You can see it in action: http://plnkr.co/UQ5q5FxyBzIeEjRYYVGX?plnkr=legacy
<input type="button" value="set to 'misko'" ng-click="data.name='misko'"/>
<input type="button" value="set to 'MISKO'" ng-click="data.name='MISKO'"/>
<input changecase ng-model="data.name" />
When you type a name in (view to model), you will see that the model is always lowercase. But, when you click a button and programatically change the name (model to view), the input field is always uppercase.
Another usage for formatters and parsers is when you want to store dates in UTC time and display them in local time on inputs, I created the below datepicker directive and utcToLocal filter for this.
(function () {
'use strict';
angular
.module('app')
.directive('datepicker', Directive);
function Directive($filter) {
return {
require: 'ngModel',
link: function (scope, element, attr, ngModel) {
element.addClass('datepicker');
element.pickadate({ format: 'dd/mm/yyyy', editable: true });
// convert utc date to local for display
ngModel.$formatters.push(function (utcDate) {
if (!utcDate)
return;
return $filter('utcToLocal')(utcDate, 'dd/MM/yyyy');
});
// convert local date to utc for storage
ngModel.$parsers.push(function (localDate) {
if (!localDate)
return;
return moment(localDate, 'DD/MM/YYYY').utc().toISOString();
});
}
};
}
})();
It uses this utcToLocal filter that ensures the input date is in the correct format before converting to local time.
(function () {
'use strict';
angular
.module('app')
.filter('utcToLocal', Filter);
function Filter($filter) {
return function (utcDateString, format) {
if (!utcDateString) {
return;
}
// append 'Z' to the date string to indicate UTC time if the timezone isn't already specified
if (utcDateString.indexOf('Z') === -1 && utcDateString.indexOf('+') === -1) {
utcDateString += 'Z';
}
return $filter('date')(utcDateString, format);
};
}
})();
moment.js is used to convert local to utc dates.
pickadate.js is the datepicker plugin used

Resources