使用 momentjs 更改 Angular Material 中 md-datepicker 的格式

Posted

技术标签:

【中文标题】使用 momentjs 更改 Angular Material 中 md-datepicker 的格式【英文标题】:Change format of md-datepicker in Angular Material with momentjs 【发布时间】:2015-12-10 13:12:09 【问题描述】:

Angular 材料引入了一个新的日期选择器组件,发现 here。

我希望此组件返回的日期格式为 yyy-mm-dd,但我不确定这是如何完成的。通过搜索发现$mdDateLocaleProvider可以使用,但是找不到使用的例子。

谁能给我看一个格式化md-datepicker返回的日期的工作示例?

【问题讨论】:

【参考方案1】:

Angular Material 文档中有$mdDateLocaleProvider 的文档。

angular.module('app').config(function($mdDateLocaleProvider) 
    $mdDateLocaleProvider.formatDate = function(date) 
       return moment(date).format('YYYY-MM-DD');
    ;
);

如果您不使用 moment.js,请将 formatDate 中的代码替换为您希望用于格式化日期的任何内容。

Here 是一个基于 Angular Material 文档示例的 CodePen 示例。

【讨论】:

这会将今天的日期设置为 datepicker。我希望它在加载时为空。我该怎么办? @AliDemirci 假设您绑定的日期是 undefined 加载时,这样的事情应该有效:return date ? moment(date).format('YYYY-MM-DD') : ''; 谢谢你的输入,但它不会返回我在 ng-model 上的格式化日期,而是给我一个类似Tue Oct 06 2015 00:00:00 GMT+0300的日期 不幸的是,如果日期是从键盘输入的,它就不起作用。例如。对于上述格式,我输入的是 2016-04-01,它返回 1 月 4 日:/ @saurabh,我已经修好了。我的用例只是将此日期值发送回服务器,但我们的 java 后端无法处理它。所以我的后端开发人员要求我在没有“.***Z”的情况下发回日期。幸运的是 moment(question.date).format('YYYY-MM-DDTHH:mm:ss') 对我有用。希望这会有所帮助【参考方案2】:

同时解决kazuar指出的问题:

不幸的是,如果从键盘输入日期,它就不起作用

您也应该定义 parseDate 方法。来自文档:

$mdDateLocaleProvider.parseDate = function(dateString) 
    var m = moment(dateString, 'L', true);
    return m.isValid() ? m.toDate() : new Date(NaN);
;

举个完整的例子,我的应用中有(使用时刻):

$mdDateLocaleProvider.formatDate = function(date) 
    return moment(date).format('DD/MM/YYYY');
;

$mdDateLocaleProvider.parseDate = function(dateString) 
    var m = moment(dateString, 'DD/MM/YYYY', true);
    return m.isValid() ? m.toDate() : new Date(NaN);
;

问候

【讨论】:

这应该是公认的答案。如果您正在使用时刻,您还需要在 $mdDateLocaleProvider 之后将其添加到您的配置参数中,如下所示:angular.module('app') .config(function ($mdDateLocaleProvider, moment) ... ) 虽然调用了这段代码,但它似乎并没有真正更新值。【参考方案3】:

对于不使用 Moment.js 的人,您可以格式化为字符串:

.config(function($mdDateLocaleProvider) 
  $mdDateLocaleProvider.formatDate = function(date) 

    var day = date.getDate();
    var monthIndex = date.getMonth();
    var year = date.getFullYear();

    return day + '/' + (monthIndex + 1) + '/' + year;

  ;
);

【讨论】:

【参考方案4】:

当从键盘输入日期并在启动时返回 null 以避免在 md-datapicker 指令中出现“无效日期”消息时,工作完美:

$mdDateLocaleProvider.formatDate = function(date) 
  return date ? moment(date).format('DD/MM/YYYY') : null;
;

$mdDateLocaleProvider.parseDate = function(dateString) 
  var m = moment(dateString, 'DD/MM/YYYY', true);
  return m.isValid() ? m.toDate() : new Date(NaN);
;

【讨论】:

这需要额外的东西吗?我试过了(虽然没有时间),代码确实被调用了,但结果并没有出现在模型中。 我在没有 moment.js 的情况下得到了这个工作。在使用它的组件中(而不是在配置阶段)我这样做:$mdDateLocale.formatDate = date => $filter('date')(date, "mediumDate"); 另一个方向由 javascript 的内置日期解析自动处理,这是非常宽容的。【参考方案5】:

-- 当我们在 md-dialog 中使用 md-DatePicker 时,$mdDateLocaleProvider 服务不会按照我们的需要格式化日期。我们必须在 md-dialog 的控制器中使用 $mdDateLocale 来格式化 md-DatePicker 的日期。例如 -

angular.module('MyApp').controller('AppCtrl', function($scope, $mdDateLocale) 

  $mdDateLocale.formatDate = function(date) 
    return moment(date).format('YYYY-MM-DD');
  ;

  $scope.myDate = new Date('2015-10-15');

  $scope.minDate = new Date();

  $scope.maxDate = new Date();
);

【讨论】:

您如何访问控制器内的时刻?您没有收到任何错误吗? 不,先生,我没有收到任何错误。只需在 index.html 页面中添加 moment.js 引用,例如 - 它对我有用。 如果您只想覆盖 1 个控制器而不是其他控制器中的格式,这是一个很棒的解决方案。谢谢 - 辛苦了!【参考方案6】:

AngularJS 1.5.9 和 moment 2.17.1 完全可以在运行时更改日期格式、月份名称和星期名称。

首先配置初始语言。 (在这个例子中,angular-translate/$translateProvider 的配置是可选的。)

angular.module('app').config(configureLocalization)

configureLocalization.$inject = ['$translateProvider', '$mdDateLocaleProvider', 'localdb', '__config'];
function configureLocalization($translateProvider, $mdDateLocaleProvider, localdb, __config) 
  // Configure angular-translate
  $translateProvider.useStaticFilesLoader(
      prefix: 'locale/',
      suffix: '.json'
  );
  // get the language from local storage using a helper 
  var language = localdb.get('language');
  if (!language || language === 'undefined') 
    localdb.set('language', (language = __config.app.defaultLanguage));
  
  // Set the preferredLanguage in angular-translate
  $translateProvider.preferredLanguage(language);

  // Change moment's locale so the 'L'-format is adjusted.
  // For example the 'L'-format is DD.MM.YYYY for German
  moment.locale(language);

  // Set month and week names for the general $mdDateLocale service
  var localeData = moment.localeData();
  $mdDateLocaleProvider.months      = localeData._months;
  $mdDateLocaleProvider.shortMonths = moment.monthsShort();
  $mdDateLocaleProvider.days        = localeData._weekdays;
  $mdDateLocaleProvider.shortDays   = localeData._weekdaysMin;
  // Optionaly let the week start on the day as defined by moment's locale data
  $mdDateLocaleProvider.firstDayOfWeek = localeData._week.dow;

  // Format and parse dates based on moment's 'L'-format
  // 'L'-format may later be changed
  $mdDateLocaleProvider.parseDate = function(dateString) 
    var m = moment(dateString, 'L', true);
    return m.isValid() ? m.toDate() : new Date(NaN);
  ;

  $mdDateLocaleProvider.formatDate = function(date) 
    var m = moment(date);
    return m.isValid() ? m.format('L') : '';
  ;

稍后您可能会有一些基本控制器来监视当用户选择另一种语言时更改的语言变量。

angular.module('app').controller('BaseCtrl', Base);

Base.$inject = ['$scope', '$translate', 'localdb', '$mdDateLocale'];
function Base($scope, $translate, localdb, $mdDateLocale) 

  var vm = this;
  vm.language = $translate.use();

  $scope.$watch('BaseCtrl.language', function(newValue, oldValue) 
    // Set the new language in local storage
    localdb.set('language', newValue);
    $translate.use(newValue);

    // Change moment's locale so the 'L'-format is adjusted.
    // For example the 'L'-format is DD-MM-YYYY for Dutch
    moment.locale(newValue);

    // Set month and week names for the general $mdDateLocale service
    var localeDate = moment.localeData();
    $mdDateLocale.months      = localeDate._months;
    $mdDateLocale.shortMonths = moment.monthsShort();
    $mdDateLocale.days        = localeDate._weekdays;
    $mdDateLocale.shortDays   = localeDate._weekdaysMin;
    // Optionaly let the week start on the day as defined by moment's locale data
    $mdDateLocale.firstDayOfWeek = localeData._week.dow;
  );

注意我们不需要更改 $mdDateLocale.formatDate$mdDateLocale.parseDate 方法,因为它们已经配置为使用通过调用 moment.locale(newValue) 更改的“L”格式。

请参阅 $mdDateLocaleProvider 的文档了解更多区域设置自定义:https://material.angularjs.org/latest/api/service/$mdDateLocaleProvider

奖励:这是语言选择器的外观:

<md-select ng-model="BaseCtrl.language" class="md-no-underline">
  <md-option
    ng-repeat="language in ['en', 'de', 'fr', 'nl']"
    ng-value ="language"
  ><span
    class    ="flag-icon flag-icon-language ==='en' ? 'gb' : language"
  ></span>
  </md-option>
</md-select>

【讨论】:

【参考方案7】:

使用$filter 而不是moment.js 并参考@Ian Poston Framer 和@java dev 对我的回复,以下终于对我有用:

angular
    .module('App', ['ngMaterial'])
    .run(function($mdDateLocale, $filter) 
        $mdDateLocale.formatDate = function(date) 
            return $filter('date')(date, "dd-MM-yyyy");
        ;
    )

我无法将$filter 注入.config,因为它不是提供程序,所以我必须在.run$mdDateLocale 中进行。

【讨论】:

【参考方案8】:

我遇到了同样的问题,并在moment.js 的帮助下想出了这个简单的解决方案。我使用了ng-change 属性,该属性在日期更改时触发。

在您的 HTML 中:

<md-datepicker ng-model="myDate" ng-change="dateChanged()"></md-datepicker>

在您的控制器内部:

$scope.dateChanged = function() 
    this.myDate = moment(this.myDate).format('YYYY/MM/DD');

【讨论】:

【参考方案9】:

对于angular-material >= 5.x.x

角度材料文档中描述了使用其他自定义/预定义日期格式的推荐方式:

https://material.angular.io/components/datepicker/overview#choosing-a-date-implementation-and-date-format-settings

使用MomentJS自定义和解析日期时间显示formats的实现示例:

...
import  MomentModule  from 'angular2-moment';

import  MatMomentDateModule, MomentDateAdapter, MAT_MOMENT_DATE_FORMATS  from '@angular/material-moment-adapter';
import  DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE from '@angular/material/core';

...

// moment formats explanation: https://momentjs.com/docs/#/displaying/format/
export const MY_FORMATS = 
    parse: 
      dateInput: 'YYYY-MM-DD',
    ,
    display: 
      dateInput: 'YYYY-MM-DD',
      monthYearLabel: 'MMM YYYY',
      dateA11yLabel: 'YYYY-MM-DD',
      monthYearA11yLabel: 'MMMM YYYY',
    ,
  ;

  ...

@Component(
    ...
    providers: [
        // `MomentDateAdapter` and `MAT_MOMENT_DATE_FORMATS` can be automatically provided by importing
        // `MatMomentDateModule` in your applications root module. We provide it at the component level
        // here, due to limitations of our example generation script.
        provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE],
        // provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS,
        provide: MAT_DATE_FORMATS, useValue: MY_FORMATS
    ]
)

...

根据您的实现,您可能还需要在组件内部使用:

date = new FormControl(moment());

您还必须为 Angular 安装 Moment 库和适配器:

https://www.npmjs.com/package/angular2-moment

npm install --save angular2-moment

https://www.npmjs.com/package/@angular/material-moment-adapter

npm install --save @angular/material-moment-adapter

【讨论】:

【参考方案10】:

我想提供 100% 基于Christiaan Westerbeek's post 的解决方案。我真的很喜欢他的做法,但我个人想要一些更简单的东西。

appConfig.js

// config params in global scope that need to be set outside of Angular (due to Angular limitiations)
var appConfig = 
    // enables the dynamic setting of md-datepicker display masks (eg. when user changes language from English to Spanish)
    date: 
        // default mask
        format: "MM/dd/yyyy",

        // md-datepicker display format
        mdFormatDate: function (date) 
            if (date && date instanceof Date) 
                return date.format(appConfig.date.format);

             else 
                return null;

            

        

    

;

app.material.config.js

// set angular material config
app.config(['$mdDateLocaleProvider', function ($mdDateLocaleProvider) 
    // this is a global object set inside appConfig.js
    $mdDateLocaleProvider.formatDate = appConfig.date.mdFormatDate;

]);

一些处理本地化/翻译/等的服务文件

// inside the service where you'd track the language/locale change
service._updateConfigDateFormat = function (theNewDateFormat) 
    // where theNewDateFormat is something like 'yyyy/MM/dd' or whatever
    daepConfig.date.format = theNewDateFormat;

;

应该注意的是,这个解决方案不会重新格式化你的 md-datepicker 的显示值。只有当模型改变值时它才会起作用。

【讨论】:

【参考方案11】:

如果您使用的是最新版本的 angular-material.js,请使用 $mdDateLocale 服务。此代码示例使用 angular 的内置日期过滤器作为使用 moment.js 库的替代方法。在此链接https://docs.angularjs.org/api/ng/filter/date 上查看使用 angular 的 $filter 服务的其他日期格式选项。

// mainController.js
angular.module('app').config(function($mdDateLocale, $filter, $scope) 

  // FORMAT THE DATE FOR THE DATEPICKER
  $mdDateLocale.formatDate = function(date) 
        return $filter('date')($scope.myDate, "mediumDate");
  ;

);

【讨论】:

【参考方案12】:

我使用$mdDateLocaleProvider 在前端格式化它。如果您想在将日期发送到后端时对其进行格式化,则以下内容对我有用:-

$filter('date')(this.date, 'MM/dd/yyyy');

我在控制器中有上述内容。

【讨论】:

【参考方案13】:

在我的情况下,我失去了 PlaceHolder 一切正常,但是当我使用自定义格式时,placeHolder 消失了。下面的行解决了我的占位符问题。

$mdDateLocaleProvider.formatDate = function (date) 
                if(date==null)
                return "";
                var m = moment(date);
                return m.isValid() ? m.format('L') : '';
            ;

【讨论】:

以上是关于使用 momentjs 更改 Angular Material 中 md-datepicker 的格式的主要内容,如果未能解决你的问题,请参考以下文章

Angular 8 - 加载垫模块的单元测试问题

momentjs的使用

使用MomentJS无法获得时差

如何在 EJS 视图中使用节点模块(如 MomentJS)?

momentjs

MomentJS 错误输出