When I get a model from the server it looks like this:
$scope.m =
{
name: "John",
Dt: "2013-10-03T18:47:33.5049087-07:00"
};
The view looks like:
<input title="Date" ui-date ng-model="m.Dt" />
I set the default date format on the jQuery datepicker to:
$.datepicker.setDefaults({dateFormat: 'mm-dd-yy'});
The initial value of the input stays "2013-10-03T18:47:33.5049087-07:00" though. It only formats as mm-dd-yy
if I use the datepicker to change the date.
How can I get the initial value to also be in mm-dd-yy
format?
When I get a model from the server it looks like this:
$scope.m =
{
name: "John",
Dt: "2013-10-03T18:47:33.5049087-07:00"
};
The view looks like:
<input title="Date" ui-date ng-model="m.Dt" />
I set the default date format on the jQuery datepicker to:
$.datepicker.setDefaults({dateFormat: 'mm-dd-yy'});
The initial value of the input stays "2013-10-03T18:47:33.5049087-07:00" though. It only formats as mm-dd-yy
if I use the datepicker to change the date.
How can I get the initial value to also be in mm-dd-yy
format?
3 Answers
Reset to default 1Your $scope.m.Dt property should be of date type, not string.
$scope.m =
{
name: "John",
Dt: new Date()
};
To set date format use ui-date-format directive, like:
<input title="Date" ui-date ui-date-format="mm-dd-yy" ng-model="m.Dt" />
See example in readme: https://github./angular-ui/ui-date#ui-date-format-directive
The problem is that the "date" is just a string, Angular wants a native Date object (or a timestamp).
I've found two ways of dealing with this: Scrub the data right away or watch the variable and reassign its type.
My preferred solution is to munge the data when it's brought in. Since I know the object has a date
, I just scrub the JSON data from the $http
success
promise like this:
$http.get('data.json').success(function(data) {
data.date = Date.parse(data.date);
$scope.model = data;
}
That converts the data before it's assigned to $scope
, so Angular will see $scope.model.date
as a native JS Date object format it correctly.
The other solution is to specifically $watch
the variable's type. Somewhere in the controller, add this:
$scope.$watch('model.date', function() {
if (typeof $scope.model.date === 'string') {
$scope.model.date = Date.parse($scope.model.date);
}
});
That checks the type everytime $scope.model.date
is modified. Obviously, that's more overhead, but might be useful in some cases.
I had the same issue. Here is what I did using Jquery-UI calendar with Angularjs
date format was "2015-03-24T04:00:00"
First trim the date string to get only year, month, and date.
var date = "2015-03-24T04:00:00"
var formattedDate = date.match(/[\d-]+/).pop();
// formattedDate is now "2015-03-24" which is passed into
// the directive below as the input.$modelValue.
Now, inside your directive or controller do the following...
// Here is directive example.
link: function( scope, element, attrs, input ){
element.datepicker( optionsObjectHere );
setInitialDateFormatOnInput();
function setInitialDateFormatOnInput(){
setTimeout(function(){ // This timeout is required to delay the directive for the input.modelValue to resolve, however, no actual delay occurs!
element.datepicker( "setDate", formatToJqueryUIDateFormat());
});
}
function formatToJqueryUIDateFormat(){
return $.datepicker.parseDate( 'yy-mm-dd', input.$modelValue );
// 'yy-mm-dd' needs to match the input.$modelValue format from above.
}
} // link
This is how I use the entire jquery UI on my inputs.
HTML
<input type="text" class="inline" ng-model="inputValue" my-calendar-popup="calendarOptions" />
Where calendarOptions is the following object
var calendarOptions = { minDate: 0, buttonImage: "calendar-icon.png", buttonImageOnly: 'true', showOn: "both", dateFormat: "MM d, yy" };
DIRECTIVE
app.directive('myCalendarPopup', function(){
var defaultOptions = { minDate: 0, buttonImage: "calendar-icon.png", buttonImageOnly: 'true', showOn: "both", dateFormat: "MM d, yy" };
// defaultOptions just in case someone doesn't pass in options.
return {
require:'?ngModel',
restrict: 'A',
link: function( scope, element, attrs, input ){
if ( !input ){ return; } // If no ngModel then return;
element.datepicker( createCalendarOptions());
setInitialDateFormatOnInput();
function createCalendarOptions(){
if( !attrs.rsCalendarPopup ){ return addRequiredJqueryFunction( defaultOptions );}
return formatOptions();
}
function formatOptions() {
var options = scope.$eval( attrs.rsCalendarPopup );
// Turn string into object above.
return addRequiredJqueryFunction( options );
}
function addRequiredJqueryFunction( options ){
options.onSelect = changeDate;
// add onSelect to passed in object and reference local changeDate function, which will update changes to input.$modelValue.
return options;
}
function changeDate( date ){
input.$setViewValue( date );
}
function setInitialDateFormatOnInput(){
setTimeout(function(){
// This timeout is required to delay the directive for the input.modelValue to resolve.
// However, there is no actual timeout time. This is a must to get
// Angular to behave.
element.datepicker( "setDate", formatToJqueryUIDateFormat());
});
}
function formatToJqueryUIDateFormat(){
return $.datepicker.parseDate( 'yy-mm-dd', input.$modelValue );
// 'yy-mm-dd' is not the format you want the calendar to be
// it is the format the original date shows up as.
// you set your actual formatting using the calendar options at
// the top of this directive or inside the passed in options.
// The key is called dateFormat, in this case it's set as
// dateFormat: "MM d, yy" which makes June 30, 2015.
}
} // link
} // return
});
Note: I can only get this to work in it's displayed configuration. I have added it to a controller, and even a directive controller and could not recreate the initial date condition. I have not found out why this is yet. Perhaps this solution works only within a link function that is embedded in another isolated scope directive and works due to specific timing.