Prometheus
Prometheus

Reputation: 33625

Model is not a date object on input in AngularJS

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?

Upvotes: 34

Views: 26019

Answers (7)

jafarbtech
jafarbtech

Reputation: 7015

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

Upvotes: 1

Usman
Usman

Reputation: 2577

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.

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

Upvotes: 0

Jakobovski
Jakobovski

Reputation: 3390

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">

Upvotes: 8

kcho0
kcho0

Reputation: 169

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!

Upvotes: 1

cs1707
cs1707

Reputation: 499

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.

Upvotes: 47

ryeballar
ryeballar

Reputation: 30098

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

Upvotes: 25

Related Questions