AngularJS input date french - angularjs

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

Related

Angular Pikaday multiple date format

I am using Pikaday date picker plugin in my angular JS app.
Is it possible to have different format for view and different format while submitting?
For ex: 01 Jan 2014 (Display)
01/01/2014 (while submitting the form)
I know i can apply a filter while posting the content. However, since the date picker is been used in many places i have to do it at all the places separately. It will be great if the plugin updates my ng-model with a certain format but displays it differently.
You can get this by using angularjs directive (formatters and parsers).
For example using moment.js:
app.directive('fdate', function () {
return {
require: 'ngModel',
link: function(elem, $scope, attrs, ngModel){
ngModel.$formatters.push(function(val)
{
return moment(val).format("DD/MM/YYYY");
});
ngModel.$parsers.push(function(val){
return moment(val, "DD/MM/YYYY").valueOf();
});
}
}
});
and in your html:
<input type="text" ng-model="obj.yourdate" fdate>
i found this fiddle as an example:
http://jsfiddle.net/arunpjohny/wNBAn/

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

Input field number format 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 :)

Angular (directive newbie): How to add date time-picker to ngModel so that it can be validated?

I am very new to Angular and have a specific use case in mind
I have a form which has two fields - Name and datetime.
The name is ng-model but datetime is not since it is not part of Angular and is a jquery component
What I want to do?
Here is the plunker = http://plnkr.co/edit/wGrvXAFmPGoYSwh9GfxH?p=preview
a.) I want to associate date to ngModel like ngModel="transaction.date"
b.) validate it as required using Angular way
Something which will look like (much like Angular)
<input type="text" name="transactionDate" ng-model="transaction.date" data-date-format="yyyy-mm-dd hh:ii" required>
Why?
a.) To to things Angular way
b.) It makes model more consistent to test, validate
I asked this question on Stackoverflow and it was recommended to use custom directive, can someone give me direction with example how to do it?
Please guide me further since I am not able to validate it currently
Thank you very much
Based on Ketan's answer, I had to write a new directive and associate the value form jQuery to ng-model, which then is validated with form. The directive looks like
app.directive('dateTime', function(){
return {
restrict: 'A',
require: '?ngModel',
link: function(scope, element, attrs, ngModel){
if (!ngModel) {
console.log('no model, returning');
return;
}
element.bind('blur keyup change', function() {
console.log('datetime changed: ', $('.form_datetime input').val());
scope.$apply(read);
});
read();
function read() {
ngModel.$setViewValue(element.val());
}
}
}
});
The plunker can be found here
Assuming you know how to write directives, you need to use the NgModelController inside your directive and use the $setViewValue(value) method. (See example the below page).
http://docs.angularjs.org/api/ng.directive:ngModel.NgModelController
This has to be called from your custom Datepicker event which triggers when the user completes the selection.

Resources