Reputation: 283293
I have an input defined as
<input class="datepicker" type="text" ng-model="clientForm.birthDate" />
Which is rigged up to be displayed elsewhere on the page:
<tr>
<th>Birth Date</th>
<td>{{client.birthDate|date:'mediumDate'}}</td>
</tr>
When the page loads the birth date is nicely formatted as something like Dec 22, 2009
. However, when I look inside my <input>
it's shown as Tue Dec 22 2009 00:00:00 GMT-0800 (Pacific Standard Time)
which I guess is how JS renders Date
objects as strings.
Firstly, how do I tell Angular to show the date in the <input>
as something like 12/22/2009
? I can't seem to apply |filters
inside the ng-model
attribute.
Secondly, as soon as I edit the date, even keeping it in it's original format, my other text (inside the <td>
) doesn't seem to apply the |date
filter anymore; it suddenly changes formats to match that of the input textbox. How do I get it to apply the |date
filter every time the model changes?
Related questions:
Upvotes: 97
Views: 266366
Reputation: 653
In Angular15 onwards There is another way to modify any data dynamically with the help of value and input
<input [value]="currentItem.name"
(input)="currentItem.name=getValue($event)">
getValue(event: Event): string {
let utcDateString = (event.target as HTMLInputElement).value;
if (utcDateString && utcDateString.includes('000Z')) {
const utcDate = new Date(utcDateString);
const year = utcDate.getUTCFullYear();
const month = String(utcDate.getUTCMonth() + 1).padStart(2, '0'); // Months are zero-based
const day = String(utcDate.getUTCDate()).padStart(2, '0');
utcDateString = `${year}-${month}-${day}`;
return utcDateString;
}
return utcDateString
}
For example, I have a date that is coming in ISO format "2024-05-31T00:00:00.000Z" and I want to convert that date to "2024-05-31" because I was directly using my Data of Object which should provide the data and update the data in the same array of objects.
dateData = [{from:"2024-05-31T00:00:00.000Z",to:"2024-05-31T00:00:00.000Z"},{from:"2024-05-31T00:00:00.000Z",to:"2024-05-31T00:00:00.000Z"}]
So the solution I have found is
<div class="col form-group">
<label for="from">Start date</label>
{{season.from}}
<input
class="form-control"
id="from_{{ inx }}"
type="date"
value="{{ season.from | date : 'yyyy-MM-dd' }}"
(input)="season.from = getValue($event)"
required
/>
</div>
</div>
<div class="col-3">
<div class="col form-group">
<label for="to">End date</label>
{{season.to}}
<input
class="form-control"
id="to_{{ inx }}"
type="date"
value="{{ season.to | date : 'yyyy-MM-dd' }}"
(input)="season.to = getValue($event)"
required
/>
</div>
Thanks !
Upvotes: 0
Reputation: 1336
In Angular2+ for anyone interested:
<input type="text" placeholder="My Date" [ngModel]="myDate | date: 'longDate'">
with type of filters in DatePipe Angular.
Upvotes: 4
Reputation: 1585
Since you have used datepicker as a class I'm assuming you are using a Jquery datepicker or something similar.
There is a way to do what you are intending without using moment.js at all, purely using just datepicker and angularjs directives.
I've given a example here in this Fiddle
Excerpts from the fiddle here:
Datepicker has a different format and angularjs format is different, need to find the appropriate match so that date is preselected in the control and is also populated in the input field while the ng-model is bound. The below format is equivalent to 'mediumDate'
format of AngularJS.
$(element).find(".datepicker")
.datepicker({
dateFormat: 'M d, yy'
});
The date input directive needs to have an interim string variable to represent the human readable form of date.
Refreshing across different sections of page should happen via events, like $broadcast
and $on
.
Using filter to represent date in human readable form is possible in ng-model as well but with a temporary model variable.
$scope.dateValString = $filter('date')($scope.dateVal, 'mediumDate');
Upvotes: 7
Reputation: 30517
Use custom validation of forms http://docs.angularjs.org/guide/forms Demo: http://plnkr.co/edit/NzeauIDVHlgeb6qF75hX?p=preview
Directive using formaters and parsers and MomentJS )
angModule.directive('moDateInput', function ($window) {
return {
require:'^ngModel',
restrict:'A',
link:function (scope, elm, attrs, ctrl) {
var moment = $window.moment;
var dateFormat = attrs.moDateInput;
attrs.$observe('moDateInput', function (newValue) {
if (dateFormat == newValue || !ctrl.$modelValue) return;
dateFormat = newValue;
ctrl.$modelValue = new Date(ctrl.$setViewValue);
});
ctrl.$formatters.unshift(function (modelValue) {
if (!dateFormat || !modelValue) return "";
var retVal = moment(modelValue).format(dateFormat);
return retVal;
});
ctrl.$parsers.unshift(function (viewValue) {
var date = moment(viewValue, dateFormat);
return (date && date.isValid() && date.year() > 1950 ) ? date.toDate() : "";
});
}
};
});
Upvotes: 73
Reputation: 91
I'm using jquery datepicker to select date. My directive read date and convert it to json date format (in milliseconds) store in ng-model
data while display formatted date.and reverse if ng-model have json date (in millisecond) my formatter display in my format as jquery datepicker.
Html Code:
<input type="text" jqdatepicker ng-model="course.launchDate" required readonly />
Angular Directive:
myModule.directive('jqdatepicker', function ($filter) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
element.datepicker({
dateFormat: 'dd/mm/yy',
onSelect: function (date) {
var ar=date.split("/");
date=new Date(ar[2]+"-"+ar[1]+"-"+ar[0]);
ngModelCtrl.$setViewValue(date.getTime());
scope.$apply();
}
});
ngModelCtrl.$formatters.unshift(function(v) {
return $filter('date')(v,'dd/MM/yyyy');
});
}
};
});
Upvotes: 7
Reputation: 1159
I prefer to have the server return the date without modification, and have javascript do the view massaging. My API returns "MM/DD/YYYY hh:mm:ss" from SQL Server.
Resource
angular.module('myApp').factory('myResource',
function($resource) {
return $resource('api/myRestEndpoint/', null,
{
'GET': { method: 'GET' },
'QUERY': { method: 'GET', isArray: true },
'POST': { method: 'POST' },
'PUT': { method: 'PUT' },
'DELETE': { method: 'DELETE' }
});
}
);
Controller
var getHttpJson = function () {
return myResource.GET().$promise.then(
function (response) {
if (response.myDateExample) {
response.myDateExample = $filter('date')(new Date(response.myDateExample), 'M/d/yyyy');
};
$scope.myModel= response;
},
function (response) {
console.log(response.data);
}
);
};
myDate Validation Directive
angular.module('myApp').directive('myDate',
function($window) {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
var moment = $window.moment;
var acceptableFormats = ['M/D/YYYY', 'M-D-YYYY'];
function isDate(value) {
var m = moment(value, acceptableFormats, true);
var isValid = m.isValid();
//console.log(value);
//console.log(isValid);
return isValid;
};
ngModel.$parsers.push(function(value) {
if (!value || value.length === 0) {
return value;
};
if (isDate(value)) {
ngModel.$setValidity('myDate', true);
} else {
ngModel.$setValidity('myDate', false);
}
return value;
});
}
}
}
);
HTML
<div class="form-group">
<label for="myDateExample">My Date Example</label>
<input id="myDateExample"
name="myDateExample"
class="form-control"
required=""
my-date
maxlength="50"
ng-model="myModel.myDateExample"
type="text" />
<div ng-messages="myForm.myDateExample.$error" ng-if="myForm.$submitted || myForm.myDateExample.$touched" class="errors">
<div ng-messages-include="template/validation/messages.html"></div>
</div>
</div>
template/validation/messages.html
<div ng-message="required">Required Field</div>
<div ng-message="number">Must be a number</div>
<div ng-message="email">Must be a valid email address</div>
<div ng-message="minlength">The data entered is too short</div>
<div ng-message="maxlength">The data entered is too long</div>
<div ng-message="myDate">Must be a valid date</div>
Upvotes: 2
Reputation: 661
Here is very handy directive angular-datetime. You can use it like this:
<input type="text" datetime="yyyy-MM-dd HH:mm:ss" ng-model="myDate">
It also add mask to your input and perform validation.
Upvotes: 38
Reputation: 358
Angularjs ui bootstrap you can use angularjs ui bootstrap, it provides date validation also
<input type="text" class="form-control"
datepicker-popup="{{format}}" ng-model="dt" is-open="opened"
min-date="minDate" max-date="'2015-06-22'" datepickeroptions="dateOptions"
date-disabled="disabled(date, mode)" ng-required="true">
in controller can specify whatever format you want to display the date as datefilter
$scope.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate'];
Upvotes: 1
Reputation: 9437
I use the following directive that makes me and most users very happy! It uses moment for parsing and formatting. It looks a little bit like the one by SunnyShah, mentioned earlier.
angular.module('app.directives')
.directive('appDatetime', function ($window) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
var moment = $window.moment;
ngModel.$formatters.push(formatter);
ngModel.$parsers.push(parser);
element.on('change', function (e) {
var element = e.target;
element.value = formatter(ngModel.$modelValue);
});
function parser(value) {
var m = moment(value);
var valid = m.isValid();
ngModel.$setValidity('datetime', valid);
if (valid) return m.valueOf();
else return value;
}
function formatter(value) {
var m = moment(value);
var valid = m.isValid();
if (valid) return m.format("LLLL");
else return value;
}
} //link
};
}); //appDatetime
In my form i use it like this:
<label>begin: <input type="text" ng-model="doc.begin" app-datetime required /></label>
<label>end: <input type="text" ng-model="doc.end" app-datetime required /></label>
This will bind a timestamp (milliseconds since 1970) to doc.begin
and doc.end
.
Upvotes: 6
Reputation: 28661
I've created a simple directive to enable standard input[type="date"]
form elements to work correctly with AngularJS ~1.2.16.
Look here: https://github.com/betsol/angular-input-date
And here's the demo: http://jsfiddle.net/F2LcY/1/
Upvotes: 8