7

我从 asp.net mvc 控制器获取日期时间值作为“2014-08-31T00:00:00Z”。当我将此值绑定到我的 angular-ui datepicker 控件时,它的状态显示为 ng-invalid ng-invalid-date。

我也从 mvc 控制器获取日期格式,因此我也在我的 html 中绑定了日期格式。

当我在第 1807 行调试 ui-bootstrap-tpls.js(最新版本)文件时

在此处输入图像描述

它总是以未定义的方式出现。我尝试了很多替代方案,但我无法成功。:(

javascript 不能正确地将 angular ui datepicker 日期转换为 UTC

所以请给出一些想法并建议我如何解决这个问题。

感谢和问候,N.Murali Krishna。

4

7 回答 7

11

我有同样的问题。问题是 Angular 需要一个实际的日期对象,而不是日期的字符串表示形式。经过大量研究后,我最终向 $httpProvider 添加了一个 transformReponse,它检查所有字符串对象以查看它们是否可以转换为日期,如果可以,则实际转换它们。

angular.module('test')
.config(['$httpProvider', function ($httpProvider) {

    // ISO 8601 Date Pattern: YYYY-mm-ddThh:MM:ss
    var dateMatchPattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;

   var convertDates = function (obj) {
      for (var key in obj) {
         if (!obj.hasOwnProperty(key)) continue;

         var value = obj[key];
         var typeofValue = typeof (value);

         if (typeofValue === 'object') {
            // If it is an object, check within the object for dates.
            convertDates(value);
         } else if (typeofValue === 'string') {
            if (dateMatchPattern.test(value)) {
               obj[key] = new Date(value);
            }
         }
      }
   }

   $httpProvider.defaults.transformResponse.push(function (data) {
      if (typeof (data) === 'object') {
         convertDates(data);
      }

      return data;
   });
}])
于 2015-10-08T13:59:40.217 回答
6

这里有几点注意事项:

  1. 首先,该datepicker指令要求ng-model是一个Date对象。这在此处记录。
  2. 其次,上面 Chet 发布(并接受)的解决方案非常严厉,因为它需要在 HTTP 响应中接收到的每个日期字符串,Date如果它与硬编码模式匹配,则将其转换为对象。这不灵活,也不容易测试。对于大多数人来说,这不是正确的解决方案。

如果在您的系统中,全局日期字符串转换是正确的行为,那么正确的 Angular 设计应该是创建一个为您执行此操作的服务。这导致我...

我们(Angular UI Bootstrap)提供了一种Date通过服务将日期字符串转换为对象的机制dateParser您可以在此处查看源代码。 注意uibDateParser:此服务名称已弃用,并在 0.14.0 版本中更改为。

于 2015-10-08T18:32:56.457 回答
6

这是我迄今为止找到的最佳解决方案:

.directive('uibDatepickerPopup', function (dateFilter, uibDateParser, uibDatepickerPopupConfig) {
    return {
        restrict: 'A',
        priority: 1,
        require: 'ngModel',
        link: function (scope, element, attr, ngModel) {
            var dateFormat = attr.uibDatepickerPopup || uibDatepickerPopupConfig.datepickerPopup;
            ngModel.$validators.date = function(modelValue, viewValue) {
                var value = viewValue || modelValue;

                if (!attr.ngRequired && !value) {
                    return true;
                }

                if (angular.isNumber(value)) {
                    value = new Date(value);
                }
                if (!value) {
                    return true;
                } else if (angular.isDate(value) && !isNaN(value)) {
                    return true;
                } else if (angular.isString(value)) {
                    var date = uibDateParser.parse(value, dateFormat);
                    return !isNaN(date);
                } else {
                    return false;
                }
            };
        }
    };
});
于 2015-11-18T22:37:38.013 回答
2

我没有足够的声誉来评论切特的回答,但非常感谢这个解决方案也对我有用!我不知道你的 Github 句柄在问题中标记你,但我在 Angular UI 下提交了一个 Github 问题,以帮助其他人找到解决方案,并希望让 Angular UI 人员调查它。再次感谢!

https://github.com/angular-ui/bootstrap/issues/4554

于 2015-10-08T17:12:43.480 回答
2

要使用格式化的日期字符串而不是 Date 对象作为 Angular Datepicker 的 ng-model,您需要创建一个包装器指令。wrapper 指令会将您的字符串解析为 Date 对象并将其传递给 datepicker。当您选择一个日期时,它会从 Date 转换回字符串。这是一个示例(Plunker):

(function () {
    'use strict';

    angular
        .module('myExample', ['ngAnimate', 'ngSanitize', 'ui.bootstrap'])
        .controller('MyController', MyController)
        .directive('myDatepicker', myDatepickerDirective);

    MyController.$inject = ['$scope'];

    function MyController ($scope) {
      $scope.dateFormat = 'dd MMMM yyyy';
      $scope.myDate = '30 Jun 2017';
    }

    myDatepickerDirective.$inject = ['uibDateParser', '$filter'];

    function myDatepickerDirective (uibDateParser, $filter) {
        return {
            restrict: 'E',
            scope: {
                name: '@',
                dateFormat: '@',
                ngModel: '='
            },
            required: 'ngModel',
            link: function (scope) {

                var isString = angular.isString(scope.ngModel) && scope.dateFormat;

                if (isString) {
                    scope.internalModel = uibDateParser.parse(scope.ngModel, scope.dateFormat);
                } else {
                    scope.internalModel = scope.ngModel;
                }

                scope.open = function (event) {
                    event.preventDefault();
                    event.stopPropagation();
                    scope.isOpen = true;
                };

                scope.change = function () {
                    if (isString) {
                        scope.ngModel = $filter('date')(scope.internalModel, scope.dateFormat);
                    } else {
                        scope.ngModel = scope.internalModel;
                    }
                };

            },
            template: [
                '<div class="input-group">',
                    '<input type="text" readonly="true" style="background:#fff" name="{{name}}" class="form-control" uib-datepicker-popup="{{dateFormat}}" ng-model="internalModel" is-open="isOpen" ng-click="open($event)" ng-change="change()">',
                    '<span class="input-group-btn">',
                        '<button class="btn btn-default" ng-click="open($event)">&nbsp;<i class="glyphicon glyphicon-calendar"></i>&nbsp;</button>',
                    '</span>',
                '</div>'
            ].join('')
        }
    }

})();
<!DOCTYPE html>
<html>

  <head>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-animate.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-sanitize.js"></script>
    <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-2.5.0.js"></script>
    <script src="example.js"></script>
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
  </head>

  <body ng-app="myExample">
    <div ng-controller="MyController">
      <p>
        Date format: {{dateFormat}}
      </p>
      <p>
        Value: {{myDate}}
      </p>
      <p>
        <my-datepicker ng-model="myDate" date-format="{{dateFormat}}"></my-datepicker>
      </p>
    </div>
  </body>

</html>

于 2017-06-23T16:00:52.260 回答
1

只是想将我的解决方案添加到此堆栈中。

app.directive('formatDate', function (dateFilter, uibDateParser, uibDatepickerPopupConfig) {
    return {
        restrict: 'A',
        priority: 1,
        require: 'ngModel',
        link: function (scope, element, attr, ngModel) {
            var dateFormat = attr.uibDatepickerPopup || uibDatepickerPopupConfig.datepickerPopup;
            ngModel.$validators.date = function(modelValue, viewValue) {
                var value = viewValue || modelValue;

                if (!attr.ngRequired && !value) {
                    return true;
                }

                if (angular.isNumber(value)) {
                    value = new Date(value);
                }
                if (!value) {
                    return true;
                } else if (angular.isDate(value) && !isNaN(value)) {
                    return true;
                } else if (angular.isString(value)) {
                    var date = new Date(value);
                    return !isNaN(date);
                } else {
                    return false;
                }
            }
            ngModel.$formatters.push(function(value) {
                return new Date(value);
            });
        }
    };
});
于 2018-07-02T17:08:19.893 回答
1

我通过将字符串转换为有效的javascript格式解决了这个问题directive

请参见此处当值最初在范围内设置时,日期选择器弹出格式不起作用

于 2018-08-12T08:54:11.933 回答