How to format a date using ng-model?

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:

  • How do I get my directive to only fire on onchange?
  • How to access arguments in a directive?

Solution 1:

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() : "";
            });
        }
    };
});

Solution 2:

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.

Solution 3:

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/

Solution 4:

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'); 
            });

        }
    };
});