34

Using AngularJS I am trying to display a date using an input type=date:

<input ng-model="campaign.date_start" type="date">

However, this gives the following error:

Error: error:datefmt
Model is not a date object

The date actually comes from a JSON API in the following format:

date_start": "2014-11-19"

I thought that I could resolve it by using a filter, but this did not work and I get the same error with:

 <input ng-model="campaign.date_start | date" type="date">

I have also tried converting the string to a date, but again I get the same error:

 $scope.campaign.date_start = Date(campaign.date_start);

What else can I try?

2
  • If you try to do in console new Date("2014-11-19");, it works fine, so problem is somewhere in you data representation. Commented Nov 6, 2014 at 15:25
  • Filter can't be used in the ng-model directive because it must be an assignable statement (I.E. you must be able to assign something to it). I haven't tried the directive approaches noted below but I did find an $http interceptor approach that converts date formatted objects to JavaScript dates. This can be found at aboutcode.net/2013/07/27/json-date-parsing-angularjs.html Commented Dec 17, 2015 at 22:06

7 Answers 7

47

You can use this directive;

angular.module('app')
.directive("formatDate", function(){
  return {
   require: 'ngModel',
    link: function(scope, elem, attr, modelCtrl) {
      modelCtrl.$formatters.push(function(modelValue){
        return new Date(modelValue);
      })
    }
  }
})

In your html;

<input type="date" ng-model="date" format-date>

$formatters

Array.<Function>

Array of functions to execute, as a pipeline, whenever the model value changes. The functions are called in reverse array order, each passing the value through to the next. The last return value is used as the actual DOM value. Used to format / convert values for display in the control.

Sign up to request clarification or add additional context in comments.

7 Comments

This is the solution I've been looking for, however, I keep getting this error Error: ngModel:datefmt Model is not a date object when I try to use it, despite running my directive at a higher priority than the built-in input[date] directive.
@threed, i bet you have more then one date input in your HTML. If so, you will get error message on every date input that does not have the format-date attribute. This had me fooled for a while.
Nice solution the problem. But I'm a bit annoyed that this problem exists in the first place. Why doesn't the framework handle this for us? Now we have to parse the serverkode (since we can't get a JavaScript Date object from a JSON-respons) or write a directive to use the date input.
Also want to mention that is also possible to manipulate the date when reading from the date input (when saving data to the server for example): Use $parsers the same way $formatters is used in the above answer.
I added an if in case your model includes a nullable date if (modelValue != null) return new Date(modelValue);
|
25

You have to instantiate campaign.date_start with Date not use it as a function.

It should look something like this (small demo):

$scope.campaign.date_start = new Date(campaign.date_start);

1 Comment

that worked with the word "new" i.e. new Date() thanks
8

cs1707's directive is a great, except if the scope value for the date is null or undefined then it will initialize a date with 1/1/1970. This is probably not optimal for most people

Below is a modified version on cs1707's directive that will leave a null/undefined model as is:

angular.module('app').directive("formatDate", function() {
    return {
        require: 'ngModel',
        link: function(scope, elem, attr, modelCtrl) {
            modelCtrl.$formatters.push(function(modelValue) {
                if (modelValue){
                    return new Date(modelValue);
                }
                else {
                    return null;
                }
            });
        }
    };
});

In your html;

<input type="date" ng-model="date" format-date>

Another Option

If you want this to apply to all inputs of type date, then there is no need to add the format-date attribute to each input element. You can use the following directive. (Be careful with this as it might interact with other custom directives in unexpected ways.)

angular.module('app').directive("input", function() {
    return {
        require: 'ngModel',
        link: function(scope, elem, attr, modelCtrl) {
            if (attr['type'] === 'date'){
                modelCtrl.$formatters.push(function(modelValue) {
                    if (modelValue){
                        return new Date(modelValue);
                    }
                    else {
                        return null;
                    }
                });
            }

        }
    };
});

In your html;

<input type="date" ng-model="date">

Comments

1

Another directive solution here:

//inside directives.js
.directive('dateField', function () {
    return {
        restrict: ' E',
        scope: {
            ngBind: '=ngModel',
            ngLabel: '@'
        },
        replace: true,
        require: 'ngModel',
        controller: function ($scope) {
            if ($scope.ngBind != null) {
                var pattern = /Date\(([^)]+)\)/;
                var results = pattern.exec($scope.ngBind);
                var dt = new Date(parseFloat(results[1]));
                $scope.ngBind = dt;
            };
        },
        templateUrl: 'templates/directives/dateField.html'
    }
})
;

Add a directive template like this:

<!-- app.directives templates/directives/dateField -->
<script id="templates/directives/dateField.html" type="text/ng-template">    
    <label class="item item-input item-stacked-label ">
        <span class="input-label">{{ngLabel}}</span>
        <input type="date" placeholder="" ng-model="ngBind" />
    </label>
</script>

And use it

<date-field ng-label="This date..." ng-model="datajson.do.date"></date-field>

Good luck!

Comments

1

Using directive to reset default angular formatters/parsers by ngModelCtrl.$formatters.length = 0; ngModelCtrl.$parsers.length = 0;

It works for input[type="date"] as well as input[type="time"]. Also works well for cordova app

HTML :

<input date-input type="time" ng-model="created_time">

Angular Directive:

app.directive('dateInput', function () {
    return {
        require: 'ngModel',
        link: function (scope, element, attr, ngModelCtrl) {
            //Angular 1.3 insert a formater that force to set model to date object, otherwise throw exception.
            //Reset default angular formatters/parsers
            ngModelCtrl.$formatters.length = 0;
            ngModelCtrl.$parsers.length = 0;
        }
    };
});

Comments

0

Another simple way using a directive:

HTML:

<input date-input type="time" ng-model="created_time">

Directive:

app.directive('dateInput', function(){
    return {
        restrict : 'A',
        scope : {
            ngModel : '='
        },
        link: function (scope) {
            if (scope.ngModel) scope.ngModel = new Date(scope.ngModel);
        }
    }
});

1 Comment

Keep in mind, while this will suffice for your initial digest, this will not work should the underlying model be changed or refreshed in another digest cycle.
0

You can avoid from this error using this piece of code which is actually a date format error while we pass our date to some function or API

            var options = {
                weekday: "long", year: "numeric", month: "short",
                day: "numeric", hour: "2-digit", minute: "2-digit"
            };
            $scope.campaign.date_start = $scope.campaign.date_start.toLocaleTimeString("en-us", options);

where en-us format = Friday‎, ‎Feb‎ ‎1‎, ‎2013‎ ‎06‎:‎00‎ ‎AM hope this will help others to solve issue, i was facing such error and resolved with this.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.