如何使用ng-model格式化日期?


93

我有一个输入定义为

<input class="datepicker" type="text" ng-model="clientForm.birthDate" />

将其显示在页面的其他位置:

<tr>
    <th>Birth Date</th>
    <td>{{client.birthDate|date:'mediumDate'}}</td>
</tr>

当页面加载时,出生日期的格式会很像Dec 22, 2009。但是,当我查看我<input>的内部时,它显示为Tue Dec 22 2009 00:00:00 GMT-0800 (Pacific Standard Time)我猜想的是JS如何将Date对象呈现为字符串。

首先,我如何告诉Angular将日期显示<input>12/22/2009?我似乎无法|filtersng-model属性内应用。

其次,一旦我编辑了日期,即使将其保留为原始格式,我的其他文本(位于中<td>)似乎也不再应用|date过滤器;它突然更改了格式以匹配输入文本框的格式。如何在|date每次模型更改时应用过滤器?


相关问题:


我对此也有问题,但是使用标准的js Date()函数提供了更简单的解决方案:$scope.departDate = new Date(); $scope.departTime = $scope.departDate.toTimeString().slice(0, 5);不需要其他过滤器或AngularJS IMO中的棘手变通办法。
boldnik 2015年

Answers:


71

使用表单的自定义验证http://docs.angularjs.org/guide/forms演示:http : //plnkr.co/edit/NzeauIDVHlgeb6qF75hX?p=preview

使用格式化程序和解析器以及MomentJS的指令)

angModule.directive('moDateInput', function ($window) {
    return {
        require:'^ngModel',
        restrict:'A',
        link:function (scope, elm, attrs, ctrl) {
            var moment = $window.moment;
            var dateFormat = attrs.moDateInput;
            attrs.$observe('moDateInput', function (newValue) {
                if (dateFormat == newValue || !ctrl.$modelValue) return;
                dateFormat = newValue;
                ctrl.$modelValue = new Date(ctrl.$setViewValue);
            });

            ctrl.$formatters.unshift(function (modelValue) {
                if (!dateFormat || !modelValue) return "";
                var retVal = moment(modelValue).format(dateFormat);
                return retVal;
            });

            ctrl.$parsers.unshift(function (viewValue) {
                var date = moment(viewValue, dateFormat);
                return (date && date.isValid() && date.year() > 1950 ) ? date.toDate() : "";
            });
        }
    };
});

4
我想创建一个格式化程序和解析器的小例子,感谢您今天的提问,我有理由这样做。
SunnyShah 2013年

1
@Mark,修复了第二个小提琴中的Nan问题。;)
SunnyShah 2013年

1
删除了第二种方法。太越野了。
SunnyShah

1
您可以使用on-change指令进行进一步的改进。stackoverflow.com/questions/14477904/...
SunnyShah

7
@SunnyShah-很棒的东西,真的很有帮助,非常感谢。我想知道为什么var dateFormat = attrs.moMediumDate;没有设置var dateFormat = attrs.moDateInput;moMediumDate,而没有设置moMediumDate,所以如果输入不是动态创建的,则永远不会选择初始格式。
toxaq

37

这是非常方便的指令angular-datetime。您可以像这样使用它:

<input type="text" datetime="yyyy-MM-dd HH:mm:ss" ng-model="myDate">

它还会将掩码添加到您的输入并执行验证。


1
我也使用了此指令,谢谢。如果将它与jQuery UI Datepicker一起使用,则必须确保datetime="<format>"属性值中指定的格式与Datepicker的dateFormat选项中指定的格式匹配。
tylerwal 2015年

1
我想知道在这里只有很少的赞成票的情况下,有没有可能找到一个完美的解决方案。日期太多了,您现在就可以在这里解决!多谢,伙计。
C0ZEN

2
我敢肯定,如果对文档进行了改进以使其更容易包含在现有的角度应用程序中,那么将会有更多的人投票赞成。
乔尔·汉森

8

我创建了一个简单的指令来启用标准 input[type="date"]表单元素能够与AngularJS〜1.2.16一起正常工作。

看这里: https //github.com/betsol/angular-input-date

这是演示:http : //jsfiddle.net/F2LcY/1/


嘿@Lorenzo,您的意思是?您能详细说明一下吗?
Slava Fomin II

年月日是法语,例如Lun Mar Mer代表星期一,Wen
Merlin

@Lorenzo我不确定我是否理解。该指令与本地化无关。您使用的格式化功能可能是从浏览器/系统中获取区域设置。如果您提供示例,我将能够提供帮助(jsfiddle)。
Slava Fomin II

1
只支持chrome,太糟糕了。
GeminiYellow 2015年

该指令的目标是支持所有平台。如果您有问题,为什么不在GitHub存储库上创建问题?我一直在回应所有问题。
Slava Fomin II

7

我正在使用jquery datepicker选择日期。我的指令读取日期并将其转换为json日期格式(以毫秒为单位),ng-model同时以格式化的日期存储在数据中。如果ng-model具有json日期(以毫秒为单位),则我的格式化程序以jquery datepicker的格式显示。

HTML代码:

<input type="text" jqdatepicker  ng-model="course.launchDate" required readonly />

角度指令:

myModule.directive('jqdatepicker', function ($filter) {
    return {
        restrict: 'A',
        require: 'ngModel',
         link: function (scope, element, attrs, ngModelCtrl) {
            element.datepicker({
                dateFormat: 'dd/mm/yy',
                onSelect: function (date) {   
                    var ar=date.split("/");
                    date=new Date(ar[2]+"-"+ar[1]+"-"+ar[0]);
                    ngModelCtrl.$setViewValue(date.getTime());            
                    scope.$apply();
                }
            });
            ngModelCtrl.$formatters.unshift(function(v) {
            return $filter('date')(v,'dd/MM/yyyy'); 
            });

        }
    };
});

天啊!!非常感谢你!我从字面上看已经两天想得到这样的答案了,但是找不到!你摇滚!
Michael Rentmeister 2015年

太棒了 我一直在寻找类似的东西。我正在为我的解决方案使用materializecss。如果有人对此this之以鼻,并且需要转换此指令以实现,只需element.datepickerelement.pickadate
IWI

7

由于您已经将datepicker用作类,所以我假设您正在使用Jquery datepicker或类似的东西。

有一种方法可以完全不使用moment.js,而仅使用datepicker和angularjs指令即可完成您的预期工作。

我在这个小提琴中给了一个例子

小提琴的节选:

  1. Datepicker具有不同的格式,而angularjs格式则不同,需要找到适当的匹配项,以便在绑定ng-model时在控件中预先选择日期,并在输入字段中填充日期。下面的格式等效于'mediumDate'AngularJS的格式。

    $(element).find(".datepicker")
              .datepicker({
                 dateFormat: 'M d, yy'
              }); 
  2. date输入指令需要具有一个临时字符串变量,以表示人类可读的日期形式。

  3. 刷新页面的不同部分应通过事件(例如$broadcast和)进行$on

  4. 在ng-model中也可以使用过滤器以人类可读的形式表示日期,但是可以使用临时模型变量。

    $scope.dateValString = $filter('date')($scope.dateVal, 'mediumDate');

6

我使用以下指令,使我和大多数用户感到非常高兴!它使用矩进行解析和格式化。看起来有点像前面提到的SunnyShah的那个。

angular.module('app.directives')

.directive('appDatetime', function ($window) {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ngModel) {
            var moment = $window.moment;

            ngModel.$formatters.push(formatter);
            ngModel.$parsers.push(parser);

            element.on('change', function (e) {
                var element = e.target;
                element.value = formatter(ngModel.$modelValue);
            });

            function parser(value) {
                var m = moment(value);
                var valid = m.isValid();
                ngModel.$setValidity('datetime', valid);
                if (valid) return m.valueOf();
                else return value;
            }

            function formatter(value) {
                var m = moment(value);
                var valid = m.isValid();
                if (valid) return m.format("LLLL");
                else return value;

            }

        } //link
    };

}); //appDatetime

在我的表单中,我这样使用它:

<label>begin: <input type="text" ng-model="doc.begin" app-datetime required /></label>
<label>end: <input type="text" ng-model="doc.end" app-datetime required /></label>

这会将时间戳记(自1970年以来的毫秒数)绑定到doc.begindoc.end


1
很容易忽略这样一个事实,即在此链接函数中,它ngModel是控制器参数的自定义标识符,而不是对的直接命名引用ngModel。这是一个以arg'ctrl'或'controller'命名的约定,可以使事情更清晰并避免混淆。
XML

谢谢!我一直在寻找一种好方法来做到这一点。不幸的是,大多数其他修复程序都涉及切换到专门为角度编写的日期选择器,而这是太多的工作。
乔希·穆奇

我尝试了您和@SunnyShah的回答,但他似乎没有用。不知道为什么。
Josh Mouch 2015年

3

在Angular2 +中,有兴趣的人可以:

<input type="text" placeholder="My Date" [ngModel]="myDate | date: 'longDate'">

DatePipe Angular 中使用过滤器类型。


Dang,我被困在传统的AngularJS中,我不得不这样做,我讨厌它!希望我有以上工作。
约旦

2

我更喜欢让服务器返回不做任何修改的日期,并让javascript进行视图按摩。我的API从SQL Server返回“ MM / DD / YYYY hh:mm:ss”。

资源资源

angular.module('myApp').factory('myResource',
    function($resource) {
        return $resource('api/myRestEndpoint/', null,
        {
            'GET': { method: 'GET' },
            'QUERY': { method: 'GET', isArray: true },
            'POST': { method: 'POST' },
            'PUT': { method: 'PUT' },
            'DELETE': { method: 'DELETE' }
        });
    }
);

控制者

var getHttpJson = function () {
    return myResource.GET().$promise.then(
        function (response) {

            if (response.myDateExample) {
                response.myDateExample = $filter('date')(new Date(response.myDateExample), 'M/d/yyyy');
            };

            $scope.myModel= response;
        },
        function (response) {
            console.log(response.data);
        }
    );
};

myDate验证指令

angular.module('myApp').directive('myDate',
    function($window) {
        return {
            require: 'ngModel',
            link: function(scope, element, attrs, ngModel) {

                var moment = $window.moment;

                var acceptableFormats = ['M/D/YYYY', 'M-D-YYYY'];

                function isDate(value) {

                    var m = moment(value, acceptableFormats, true);

                    var isValid = m.isValid();

                    //console.log(value);
                    //console.log(isValid);

                    return isValid;

                };

                ngModel.$parsers.push(function(value) {

                    if (!value || value.length === 0) {
                         return value;
                    };

                    if (isDate(value)) {
                        ngModel.$setValidity('myDate', true);
                    } else {
                        ngModel.$setValidity('myDate', false);
                    }

                    return value;

                });

            }
        }
    }
);

的HTML

<div class="form-group">
    <label for="myDateExample">My Date Example</label>
    <input id="myDateExample"
           name="myDateExample"
           class="form-control"
           required=""
           my-date
           maxlength="50"
           ng-model="myModel.myDateExample"
           type="text" />
    <div ng-messages="myForm.myDateExample.$error" ng-if="myForm.$submitted || myForm.myDateExample.$touched" class="errors">
        <div ng-messages-include="template/validation/messages.html"></div>
    </div>
</div>

template / validation / messages.html

<div ng-message="required">Required Field</div>
<div ng-message="number">Must be a number</div>
<div ng-message="email">Must be a valid email address</div>
<div ng-message="minlength">The data entered is too short</div>
<div ng-message="maxlength">The data entered is too long</div>
<div ng-message="myDate">Must be a valid date</div>

1

Angularjs ui bootstrap 可以使用angularjs ui bootstrap,它还提供日期验证

<input type="text"  class="form-control" 
datepicker-popup="{{format}}" ng-model="dt" is-open="opened" 
min-date="minDate" max-date="'2015-06-22'"  datepickeroptions="dateOptions"
date-disabled="disabled(date, mode)" ng-required="true"> 



在控制器中可以指定要显示日期的任何格式,如datefilter

$ scope.formats = ['dd-MMMM-yyyy','yyyy / MM / dd','dd.MM.yyyy','shortDate'];


你没有必要实施指令只是单输入字段
P.JAYASRI
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.