单击时Angular Material md-datepicker会引发错误

Posted

技术标签:

【中文标题】单击时Angular Material md-datepicker会引发错误【英文标题】:Angular Material md-datepicker throws error when clicked 【发布时间】:2015-12-23 00:40:54 【问题描述】:

我是新来的,最近使用 Angular Material 0.11.0 提供的 md-datepicker 时遇到了一些问题: https://material.angularjs.org/0.11.0/#/demo/material.components.datepicker

简而言之,我的应用程序允许用户添加带有名称和描述的单个项目。他们还能够更新相关的项目详细信息。

添加和更新都是通过 Material Designs mdDialog 完成的。 一旦用户点击添加或更新,控制器就会调用相关函数,该函数调用我工厂中的相应函数。

工厂函数包含我配置的 $mdDialog 服务。 在添加 md-datepicker 之前,我能够毫无问题地更新和添加。

点击编辑时出现以下错误。

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)

环顾四周,我发现我应该配置 md-datepicker。 我从https://material.angularjs.org/HEAD/#/api/material.components.datepicker/service/$mdDateLocaleProvider 中获得灵感,并将以下代码作为 .config 添加到我的主要 AngularJS 应用程序中(我正在使用 momentjs 根据用户的语言环境为用户提供日期)。

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

现在我可以在我的“添加”工厂中添加具有以下代码的项目。我什至可以添加我选择的日期,并且可以在纪元时间内将其保存到 Firebase。

        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
        )

当我专门点击 md-datepicker 的日历图标来更改日期时(一旦打开更新 $mdDialog)就会出现问题。

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

此时 md-datepicker 不知道它是哪一年,从 1933 年左右开始。奇怪的是,如果我不点击图标并先更改输入中的日期,我可以点击带来的图标在正确的日期列出日历。只要我当前的 mdDialog 没有关闭,我就可以做到这一点。然后,当我单击更新时,它有时会更新 firebase 上的日期。我仍然没有弄清楚为什么它不一致。通过控制器调用以下代码来更新项目


。如果我保持 md-datepicker 不变,我可以很好地更改我的其他数据。

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

我一直在这个问题上停留一段时间没有解决方案,希望能对此有所了解。谢谢大家的时间。


【问题讨论】:

你能不能提供小提琴它会更容易解决哟 嗨,我很难让它在 JSFiddle 上工作。只是没有回应。我会添加我发现的其他内容 根据您的范围,我们目前发现 $mdDialog 和 clickOutsideToClose: true 存在问题。可能取决于您的范围。试试把它改成false,看看能不能正常运行! 嗨,我试过了,到目前为止没有任何区别。目前正在处理其他事情,并将返回以进一步调查。我会记住范围界定。感谢您的建议! FWIW,我遇到了这个问题,因为我的 init 模型的日期不是 javascript Date 对象(它是 moment.format())。使用new Date() 可以解决问题。见material.angularjs.org/latest/api/directive/mdDatepicker 【参考方案1】:

在添加 $mdDateLocaleProvider 的配置之前,我遇到了与您相同的问题。我不断收到 TypeError: date.toLocaleDateString is not a function。

我也在使用 firebase 并且能够毫无问题地推送。我什至可以查看带有保存结果的日期选择器,只有在 ref.update 上我才会收到错误消息。我花了相当多的时间来寻找这个错误,最后发现由于 angular 的摘要循环,angular 材料通过它的 date 函数运行了我的日期两次,而第二次使用的是 js Date 对象的字符串表示,而不是日期 obj 本身。 (因此 TypeError: date.toLocaleDateString 不是函数 - 因为它将日期视为字符串而不是日期对象。)

不幸的是,我无法在我的实际应用程序中提出修复程序,因此我不得不进入 angular-material.js 源代码,并且在发生错误之前,我获取了传入的日期并确保它是转换为日期 (d = new Date(d));

这对我有用,因为它始终是日期或日期的 toString - 无论哪种方式,它都能确保它是一个实际的日期对象。

【讨论】:

嗨凯尔!我明白了,我需要阅读更多关于消化周期的信息,但我看到了图片。您是否在 CalendarCtrl.prototype.getDateid 上的第 6423 行附近对 angular-material 文件进行了更改?我尝试在返回函数之前添加 date = new Date(date) ,但仍然出现错误。你到底在哪里添加你的代码?我假设您已经配置了 $mdDateLocaleProvider,您使用了时刻吗?再次感谢您的帮助。 我的错误是在 DateLocaleProvider.prototype.$get 7157 左右触发的。但是,它仍然是相同的一般想法,该日期没有被视为 Date obj。所以你仍然会得到这个错误的唯一方法是如果 date = new Date(date) 没有产生一个有效的日期 obj,这意味着“日期”不能是一个有效的日期 obj 或一个有效的日期字符串 - 你能登录还是在里面打个断点看看 date 在进入 date = new Date(date) 之前的值是多少? 嘿凯尔!谢谢你的帮助!我终于看了看。我能够按照你的建议让它工作。我不必更改源代码中的任何内容。我会在答案中发布。【参考方案2】:

以下代码保留在问题中。

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

这消除了“TypeError: date.toLocaleDateString is not a function”错误。

自始至终,我只对时代感兴趣。 我没有意识到 md-datepicker 只喜欢日期对象。这解释了为什么我无法更新 project.deadline 因为它正在读取纪元时间。它可以很好地看到它,但是更改它会导致错误,因为它无法识别要显示的日期(因此显示 1934 ..)。

相反,我专注于仅处理日期对象的日期选择器。

添加新项目:

var date 是来自 md-datepicker 的日期对象形式的输入。 然后我将其转换为纪元,因此将其保存到 firebase,就像其他值一样。

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

更新项目:

将 currentProject 分配给 vm.project。这使我可以访问 vm.project.deadline ,其中包括我在纪元时间内添加的截止日期。将截止日期从纪元时间转换为日期对象。这使我可以随意更改日期。一旦用户点击更新,新的日期对象首先被转换为纪元,然后我可以像其他数据一样添加到 firebase。

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

我需要时代,因此需要转换。如果不需要纪元(或其他日期形式),我想保持日期对象不变应该没有问题。

【讨论】:

【参考方案3】:

我遇到了类似的错误,原因是我为输出(日期->字符串)定义了$mdDateLocale.formatDate,但我没有为输入(字符串->日期)定义$mdDateLocale.parseDate。一旦我这样做了,错误就消失了。

请注意,这两个函数都必须处理在 Angular 的摘要周期中可能是未定义/字符串/日期的输入。因此,请务必在 .split 或 .parse 之前测试输入。

【讨论】:

以上是关于单击时Angular Material md-datepicker会引发错误的主要内容,如果未能解决你的问题,请参考以下文章

Angular 8 Material 表在单击时突出显示一行并在单击其他行后保留背景颜色

验证失败时阻止表单提交(Angular Material)

Angular Material Snackbar 未正确显示

Angular Material 2 Form 不显示

如何使用 Angular-Material 获得全高侧导航

Angular 2 Material MdSnackBar 没有提供者