4
votes

I'm new here and have been having some problems with the recently available md-datepicker by Angular Material 0.11.0: https://material.angularjs.org/0.11.0/#/demo/material.components.datepicker

In short, my app allows users to add individual projects with name and description. They are also able to update relevant project details.

Both adding and updating are done in through Material Designs mdDialog. Once a user clicks add or update, the controller calls the relevant function which calls a corresponding function in my factory.

The factory functions contain the $mdDialog service which I have configured. I was able to update and add without any problems until I added the md-datepicker.

I got the following error when I clicked to edit.

TypeError: date.toLocaleDateString is not a function
at Object.defaultFormatDate [as formatDate] (angular-material.js:6858)
at DatePickerCtrl.configureNgModel.ngModelCtrl.$render (angular-material.js:7182)
at Object.ngModelWatch (angular.js:25353)
at Scope.parent.$get.Scope.$digest (angular.js:15751)
at Scope.parent.$get.Scope.$apply (angular.js:16030)
at done (angular.js:10545)
at completeRequest (angular.js:10717)
at XMLHttpRequest.requestLoaded (angular.js:10658)

After looking around, I figured out that I should configure the md-datepicker. I took inspiration form https://material.angularjs.org/HEAD/#/api/material.components.datepicker/service/$mdDateLocaleProvider and added the following code as .config to my main AngularJS App (I am using momentjs to give users date based on their locale).

app.config(function($mdDateLocaleProvider) {
$mdDateLocaleProvider.formatDate = function(date) {
   return moment(date).format('L');
};});

Now I can add a project with the following code in my 'add' factory. I can even add a date of my choice and I can save it to firebase in epoch time.

        return $mdDialog.show({
            clickOutsideToClose: true,
            controller: function($mdDialog) {
                var vm = this;
                vm.project = project;
                vm.add = function(project) {
                    var date = new Date();
                    project.deadline = date.getTime();

                    if(project.deadline == undefined) {
                        project.deadline = null;
                    };

                    FBprojects.$add(project);
                    console.log(project);
                    $mdDialog.hide();
                };
            },
            controllerAs: 'PAmodal',
            templateUrl: 'views/newproject.html',
            targetEvent: e
        })

The problem arises when I specifically click on the calendar icon of md-datepicker to change the date (once update $mdDialog is open).

TypeError: date.getFullYear is not a function
at CalendarCtrl.getDateId (angular-material.js:6427)
at angular-material.js:6349
at processQueue (angular.js:14678)
at angular.js:14694
at Scope.parent.$get.Scope.$eval (angular.js:15922)
at Scope.parent.$get.Scope.$digest (angular.js:15733)
at Scope.parent.$get.Scope.$apply (angular.js:16030)
at HTMLButtonElement.<anonymous> (angular.js:23486)
at HTMLButtonElement.jQuery.event.dispatch (jquery.js:4435)
at HTMLButtonElement.jQuery.event.add.elemData.handle (jquery.js:4121)(anonymous function) @ angular.js:12450ident.$get @ angular.js:9237processQueue @ angular.js:14686(anonymous function) @ angular.js:14694parent.$get.Scope.$eval @ angular.js:15922parent.$get.Scope.$digest @ angular.js:15733parent.$get.Scope.$apply @ angular.js:16030(anonymous function) @ angular.js:23486jQuery.event.dispatch @ jquery.js:4435jQuery.event.add.elemData.handle @ jquery.js:4121

Uncaught TypeError: end.getFullYear is not a function

TypeError: date.getFullYear is not a function
at CalendarCtrl.getDateId (http://localhost:9000/bower_components/angular-material/angular-material.js:6427:12)
at CalendarCtrl.focus (http://localhost:9000/bower_components/angular-material/angular-material.js:6298:23)
at http://localhost:9000/bower_components/angular-material/angular-material.js:7372:30
at http://localhost:9000/bower_components/angular-material/angular-material.js:1068:11
at Array.forEach (native)
at processQueue (http://localhost:9000/bower_components/angular-material/angular-material.js:1067:15)
at http://localhost:9000/bower_components/angular/angular.js:17788:31
at completeOutstandingRequest (http://localhost:9000/bower_components/angular/angular.js:5498:10)
at http://localhost:9000/bower_components/angular/angular.js:5775:7

At this point the md-datepicker doesnt know which year it is and start at around the year 1933. Strangely if I don't click on the icon and change the date in the input first, I can click the icon which brings out the calendar on a correct date. I can do this as long as my current mdDialog is not closed. Then, when I click update, it sometimes updates the date on firebase. I still have no figured out why it is not consistent. The following code is called via controller for updating project


. If I leave the md-datepicker untouched, I can change my other data fine.

        updateProject: function(e, currentProject) {
        return $mdDialog.show({
            clickOutsideToClose: true,
            controller: function($mdDialog) {
                var vm = this;
                vm.project = {};
                vm.project = currentProject;

                var pid = $stateParams.pid;
                var n = vm.project.deadline;
                var d = new Date(n).toString();

                vm.update = function() {
                    //Updates at FB locations with updated project
                    ref.child('projects').child(pid).update({
                        title: vm.project.title,
                        description: vm.project.description,
                        deadline: d
                    });
                    $mdDialog.hide();
                };
            },
            controllerAs: 'PEmodal',
            templateUrl: 'views/updateproject.html',
            parent: angular.element(document.body),
            targetEvent: e
        });

I have been stuck on this problem for sometime with no solution, and would appreciate some light on this. Thank you all for your time.


3
Can you please provide fiddle it will be easier to solver yoMr.M
Hi, I am having difficulties getting it to work on JSFiddle. Just no response. I'll add in other things I discoverRahul Verma
Depending on your scope, there's currently issues we've found with $mdDialog and clickOutsideToClose: true. May be dependent on your scoping. Try changing it to false to see if you can get it functioning!Ryan Drake
Hi, I gave that a try and made no difference as of now. Currently working on other things and will return to investigate this further. I will bear in mind the scoping. Thanks for your suggestion!Rahul Verma
FWIW, I was having this trouble because my init model's date was not a JavaScript Date object (it was a moment.format()). Using new Date() fixes the thing. See material.angularjs.org/latest/api/directive/mdDatepickerQuentin Klein

3 Answers

0
votes

I had the same issue as you did before you added the configuration of $mdDateLocaleProvider. I kept getting TypeError: date.toLocaleDateString is not a function.

I was also using firebase and was able to push without any problems. I could even view the datepicker with the saved result, it was only on ref.update that I would get the error. I spent quite a bit of time hunting down the bug and finally discovered that angular material was running my date through it's date function twice due to angular's digest cycle and the second time through it was using the string representation of the js Date object and not the Date obj itself. (hence the TypeError: date.toLocaleDateString is not a function - because it was treating date as the String and not a date Obj.)

Unfortunately, I could not come up with a fix in my actual app so I had to go into the angular-material.js source and right before the error hit I took the date that was being passed in and ensured it was being converted to a date (d = new Date(d));

This worked for me as it was always either a date or the toString of the date - either way it ensures that it's a actual date object.

0
votes

The following code was left as it is in the question.

app.config(function($mdDateLocaleProvider) {
$mdDateLocaleProvider.formatDate = function(date) {
   return moment(date).format('L');
};});

This eradicates the 'TypeError: date.toLocaleDateString is not a function' error.

Throughout I have only been interested in the epoch. I didn't realise that the md-datepicker only likes date objects. This explains why I could not update project.deadline as it was reading epoch time. It was able to see it fine, but changing it resulting in errors as it could not identify which date to show (hence showing 1934..).

Instead I focused on dealing with datepicker only with date objects.

Adding new project:

  • var date is the input from md-datepicker in date Object form. I then convert it into epoch so save it to firebase just like the other values.

    var date = new Date(project.deadline);
    project.deadline = date.getTime();
    

Updating project:

  • Assigning currentProject to vm.project. This gives me access to vm.project.deadline which includes the deadline I added in epoch time. Convert deadline from epoch time to date object. This allows me to change the date as I like. Once the user clicks update, the new Date Object is first converted into epoch and then I can add to firebase just like other data.

    var vm = this;
    vm.project = {};
    vm.project = currentProject;
    
    vm.project.deadline = new Date(vm.project.deadline);
    
    vm.update = function() {
        var date = new Date(vm.project.deadline);
        vm.project.deadline = date.getTime();
        ...
    

I needed the epoch times hence the conversions. If one has no need for epoch (or other date forms) I imagine leaving the date object unchanged should have no problem.

0
votes

I had a similar error and the cause turned out to be that I was defining $mdDateLocale.formatDate for output (Date->string) but I had not defined $mdDateLocale.parseDate for input (string->Date). Once I did that, the error went away.

Note that both functions have to deal with input that could be undefined/string/Date during Angular's digest cycle. So be sure to test the input before you .split or .parse or whatever.