Angular.js 和 HTML5 日期输入值——如何让 Firefox 在日期输入中显示可读的日期值?

Posted

技术标签:

【中文标题】Angular.js 和 HTML5 日期输入值——如何让 Firefox 在日期输入中显示可读的日期值?【英文标题】:Angular.js and HTML5 date input value -- how to get Firefox to show a readable date value in a date input? 【发布时间】:2013-08-06 08:56:09 【问题描述】:

我有一个 html5 日期输入,我希望它的值默认设置为我的模型中日期属性的值。我对格式并不太挑剔,因为 Chrome 似乎会根据我的语言环境为我决定,但理想情况下格式应该是一致的 dd/MM/yyyy

Fiddle

这就是我设置输入的方式:

<input type="date" 
       ng-model="date" 
       value=" date | date: 'yyyy-MM-dd' " />

这在 Chrome 上运行良好,默认情况下我会看到以下内容:

(我仍然不太明白为什么必须在 yyyy-MM-dd 中给出值,如果 Chrome 仍然根据我的语言环境对其进行格式化,但这是一个不同的问题。)

我的问题是 Firefox 没有按照我指定的方式显示日期值。我认为这与将输入绑定到date 模型有关,因为我可以在value 属性中指定几乎任何字符串,并且默认情况下我仍然会在输入中看到长日期字符串:

如果我从输入标签中删除ng-model="date",Firefox 会很好地显示我给它的任何值。我不认为输入绑定的模型实际上对其默认值有任何影响?

我知道日期输入不受普遍支持,但鉴于它应该依赖于简单的文本输入,我不明白为什么它的值不会只是 2013-08-05,正如 angular 的日期所指定的那样过滤器。

那么,如何让 Firefox 在日期输入中接受我的格式化值?


注意 在用户完成编辑后,我当然会执行验证并将每个日期输入值转换为正确的Date 对象。不确定这是否与问题相关,但将其放在那里以防万一,因为输入格式显然需要保持一致,以便日期转换在所有浏览器中都一样。当然,Chrome 为我决定输入格式是有问题的......

【问题讨论】:

您在初始化时是否尝试过正确的格式(如此处:jsfiddle.net/DotDotDot/Vq65z/7)?可能是这样的:$scope.date = $filter('date')(new Date(),'MM/dd/yyyy') @DotDotDot 这很好用,因为在这种情况下日期将是一个字符串。但是,我更喜欢将日期作为实际的 javascript 日期对象,因为我需要以各种方式对其进行操作,而且它也更具语义性。但基本上你的建议是我目前的黑客,是的。我为输入绑定的模型及其值使用了一个临时字符串,并将其转换为表单提交的日期。 我不同意闭包,因为它是一个主题,描述了重现它的代码问题,并说明了问题所在。 【参考方案1】:

问题是value is ignored when ng-model is present。

目前不支持type="date" 的Firefox 会将所有值转换为字符串。由于您(正确地)希望 date 成为真正的 Date 对象而不是字符串,我认为最好的选择是创建另一个变量,例如 dateString,然后链接这两个变量:

<input type="date" ng-model="dateString" />
function MainCtrl($scope, dateFilter) 
    $scope.date = new Date();

    $scope.$watch('date', function (date)
    
        $scope.dateString = dateFilter(date, 'yyyy-MM-dd');
    );

    $scope.$watch('dateString', function (dateString)
    
        $scope.date = new Date(dateString);
    );

Fiddle

实际结构仅用于演示目的。您最好创建自己的指令,尤其是为了:

允许yyyy-MM-dd以外的格式, 能够使用NgModelController#$formattersNgModelController#$parsers 而不是人工的dateString 变量(请参阅有关此主题的documentation)。

请注意我使用了yyyy-MM-dd,因为它是JavaScript Date 对象直接支持的格式。如果您想使用另一个,您必须自己make the conversion。


编辑

这里有一个干净的指令:

myModule.directive(
    'dateInput',
    function(dateFilter) 
        return 
            require: 'ngModel',
            template: '<input type="date"></input>',
            replace: true,
            link: function(scope, elm, attrs, ngModelCtrl) 
                ngModelCtrl.$formatters.unshift(function (modelValue) 
                    return dateFilter(modelValue, 'yyyy-MM-dd');
                );

                ngModelCtrl.$parsers.unshift(function(viewValue) 
                    return new Date(viewValue);
                );
            ,
        ;
);

Fiddle

这是一个基本指令,还有很大的改进空间,例如:

允许使用自定义格式而不是 yyyy-MM-dd, 检查用户输入的日期是否正确。

【讨论】:

谢谢,我开始认为自己需要一些中间字符串变量来替换绑定到我的日期输入的模型。你说我应该为此创建指令来隔离字符串变量——我是否理解当输入的值发生变化时更新我的​​实际date 模型,并且根本不将输入绑定到模型? 酷,我正要开始使用 this 作为粗略指南,看起来技术差不多! 如果您已经使用文本输入,则不需要templatereplace。例如,我正在使用 angular-ui-datetimepicker,它是应用于文本输入的指令。我使用了相同的代码,它可以工作。 很好的答案。非常感谢您与我们分享。我的投票 + @vp_arth 这个答案无论如何都需要重写,特别是要使编辑不那么明显。我会考虑你的 cmets,非常感谢。【参考方案2】:

为什么必须在 yyyy-MM-dd 中给出值?

根据 HTML 5 的input type = date spec,该值必须采用yyyy-MM-dd 的格式,因为它采用RFC3339 中指定的有效full-date 的格式

full-date = date-fullyear "-" date-month "-" date-mday

与Angularjs无关,因为指令输入不支持date类型。

如何让 Firefox 接受我在日期输入中的格式化值?

FF 不支持 date 类型的输入,至少直到版本 24.0。您可以从here 获取此信息。所以现在,如果你在 FF 中使用类型为 date 的输入,文本框将采用你传入的任何值。

我的建议是您可以使用Angular-ui's Timepicker,并且不要使用 HTML5 支持来输入日期。

【讨论】:

如果我不能自己破解它,我肯定会考虑 Angular 的时间选择器,尽管我想知道是否支持自定义样式......【参考方案3】:

你可以用这个,效果很好:

<input type="date" class="form1"  
  value="date | date:MM/dd/yyyy"
  ng-model="date" 
  name="id" 
  validatedateformat 
  data-date-format="mm/dd/yyyy"
  maxlength="10" 
  id="id" 
  calendar 
  maxdate="todays"
  ng-click="openCalendar('id')">
    <span class="input-group-addon">
      <span class="glyphicon glyphicon-calendar" ng-click="openCalendar('id')"></span>
    </span>
</input>

【讨论】:

openCalendar 基于什么? 的关闭标签是否违反了 w3c void 元素规范? ...也许更重要的是,这是否会对浏览器产生负面影响或解析器问题。【参考方案4】:

就我而言,我是这样解决的:

$scope.MyObject = // get from database or other sources;
$scope.MyObject.Date = new Date($scope.MyObject.Date);

输入类型日期就可以了

【讨论】:

【参考方案5】:

我用过 ng-change:

Date.prototype.addDays = function(days) 
  var dat = new Date(this.valueOf());
  dat.setDate(dat.getDate() + days);
  return dat;


var app = angular.module('myApp', []);

app.controller('DateController', ['$rootScope', '$scope',
  function($rootScope, $scope) 
    function init() 
      $scope.startDate = new Date();
      $scope.endDate = $scope.startDate.addDays(14);
    


    function load() 
      alert($scope.startDate);
      alert($scope.endDate);
    

    init();
    // public methods
    $scope.load = load;
    $scope.setStart = function(date) 
      $scope.startDate = date;
    ;
    $scope.setEnd = function(date) 
      $scope.endDate = date;
    ;

  
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-controller="DateController">
  <label class="item-input"> <span class="input-label">Start</span>
    <input type="date" data-ng-model="startDate" ng-change="setStart(startDate)" required validatedateformat calendar>
  </label>
  <label class="item-input"> <span class="input-label">End</span>
    <input type="date" data-ng-model="endDate" ng-change="setEnd(endDate)" required validatedateformat calendar>
  </label>
  <button button="button" ng-disabled="planningForm.$invalid" ng-click="load()" class="button button-positive">
    Run
  </button>
</div <label class="item-input"> <span class="input-label">Start</span>
<input type="date" data-ng-model="startDate" ng-change="setStart(startDate)" required validatedateformat calendar>
</label>
<label class="item-input"> <span class="input-label">End</span>
  <input type="date" data-ng-model="endDate" ng-change="setEnd(endDate)" required validatedateformat calendar>
</label>

【讨论】:

【参考方案6】:

检查 MEAN.JS(Angular.js、bootstrap、Express.js 和 MongoDb)的这个功能齐全的指令

根据@Blackhole 的回复,我们刚刚完成了它可以与mongodb 和express 一起使用。

它将允许您从猫鼬连接器保存和加载日期

希望对你有帮助!!

angular.module('myApp')
.directive(
  'dateInput',
  function(dateFilter) 
    return 
      require: 'ngModel',
      template: '<input type="date" class="form-control"></input>',
      replace: true,
      link: function(scope, elm, attrs, ngModelCtrl) 
        ngModelCtrl.$formatters.unshift(function (modelValue) 
          return dateFilter(modelValue, 'yyyy-MM-dd');
        );

        ngModelCtrl.$parsers.push(function(modelValue)
           return angular.toJson(modelValue,true)
          .substring(1,angular.toJson(modelValue).length-1);
        )

      
    ;
  );

JADE/HTML:

div(date-input, ng-model="modelDate")

【讨论】:

【参考方案7】:

如果使用 Angular Material Design,你可以在那里使用 datepicker 组件,这将适用于 Firefox、IE 等。

https://material.angularjs.org/latest/demo/datepicker

不过警告是公平的 - 个人经验是这方面存在问题,目前似乎正在重新设计。见这里:

https://github.com/angular/material/issues/4856

【讨论】:

以上是关于Angular.js 和 HTML5 日期输入值——如何让 Firefox 在日期输入中显示可读的日期值?的主要内容,如果未能解决你的问题,请参考以下文章

vbscript HTML5输入类型日期 - 为日期选择器指定默认值

vbscript HTML5输入类型日期 - 为日期选择器指定默认值

指定 HTML5 输入类型的值输出 = 日期?

Angular.js

Angular JS HTML5 验证

发布一个空的html5日期输入今天发送