将保存时间戳的 ng-model 绑定到 datetime-local 输入

Bind ng-model holding a timestamp to datetime-local input

我正在尝试使用 ng-model 表示时间戳来呈现 <input type="datetime-local> 字段:

<input type="datetime-local" ng-model="object.value">

$scope.object.value = 1433109600000;

控制台显示 [ngModel:datefmt] 错误。

如何正确地将 $scope.object.value 绑定到输入字段? (时间戳来自嵌套对象中的网络服务)

一些 Plnkr:http://plnkr.co/edit/TGpKVNF1tv0b1h6JPBT8?p=preview

必须是日期对象:

$scope.object = {
  name: 'Demo',
  value: new Date(1433109600000)
}

Updated demo

或者创建一个指令:

app.directive('bindTimestamp', function () {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function (scope, element, attrs, ngModel) {
      ngModel.$formatters.push(function (value) {
        return new Date(value);
      });
    }
  };
});

Directive demo

完成@karaxuna 的回答,感谢他,以下是完整的指令及其测试:

directivesApp.directive('bindTimestamp', function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ngModel) {

            var minDate = attrs.min ? new Date(attrs.min) : null;
            var maxDate = attrs.max ? new Date(attrs.max) : null;

            ngModel.$formatters.push(function (value) {
                var dt = value;
                if (!angular.isDate(dt) && angular.isNumber(dt)) {
                    // It's a timestamp --> needs to be converted to a <Date>
                    dt = new Date(value);
                }
                // truncate 'dt' to second if milliseconds are not to be displayed in input[datetime-local]
                // dt.setMilliSeconds(0);
                // truncate 'dt' to minute if seconds are not to be displayed in input[datetime-local]
                // dt.setSeconds(0);
                return dt;
            });

            // Default validators need to be overriden, otherwise they will always trigger "false" as they expect a <Date> object and not a number.
            var MinMaxValidator = function (modelValue) {
                var selectedDate = angular.timestampToDate(modelValue, scope.truncateSeconds);
                this.validate = function (validateThreshold) {
                    if (angular.isDate(selectedDate)) {
                        return validateThreshold(selectedDate);
                    }
                    return true;
                };
            };

            if (ngModel.$validators.min && minDate !== null) {
                ngModel.$validators.min = function (modelValue) {
                    return new MinMaxValidator(modelValue).validate(function (selectedDate) {
                        return minDate <= selectedDate;
                    });
                };
            }

            if (ngModel.$validators.max && maxDate !== null) {
                ngModel.$validators.max = function (modelValue) {
                    return new MinMaxValidator(modelValue).validate(function (selectedDate) {
                        return maxDate >= selectedDate;
                    });
                };
            }
        }
    };
});

茉莉花测试: 描述('bindTimestamp : timestamps',函数(){

    // 2016-02-19 09:56:51.396ms
    var dt = 1455872211396;

    function buildInputDateElement(inputType) {
        var element = angular.element('<input type="' + inputType + '" ng-model="myDate" bind-timestamp>');
        $compile(element)($scope);
        $scope.$digest();
        return element;
    }

    it('bindTimestamp : input[date]', function () {

        var formatedDate = '2016-02-19';

        /** A timestamp */
        $scope.myDate = dt;
        var element = buildInputDateElement("date");
        expect(element.val()).toEqual(formatedDate);

        //** Already a <Date> */
        $scope.myDate = new Date(dt);
        element = buildInputDateElement("date");
        expect(element.val()).toEqual(formatedDate);
    });

    it('bindTimestamp : input[datetime-local]', function () {

        var formatedDate = '2016-02-19T09:56:51.396';

        /** A timestamp */
        $scope.myDate = dt;
        var element = buildInputDateElement("datetime-local");

        expect(element.val()).toEqual(formatedDate);

        /** Already a <Date> */
        $scope.myDate = new Date(dt);
        element = buildInputDateElement("datetime-local");
        expect(element.val()).toEqual(formatedDate);
    });
});