【问题标题】:How to change date picker formcontrol value format with moment in angular material如何使用角度材料中的时刻更改日期选择器表单控件值格式
【发布时间】:2018-06-25 09:14:21
【问题描述】:

我按照material.angular.io 上的示例了解如何将时刻与材料日期选择器一起使用,并通过提供 MAT_DATE_FORMATS 来更改默认格式。示例是here。注意:代码在 stackblitz 中无法正常工作,它似乎忽略了提供的日期格式,但在我的环境中确实可以正常工作。

我的问题是当我访问表单控件的值并将其转换为 JSON 时,它总是输出“2018-01-16T15:44:33.897Z”。我需要它只输出日期“2018-01-16”。此外,我更希望日期选择器根本不添加时间属性。我怎样才能按照我想要的方式进行这项工作?

我知道你可以调用 moment 的 format 函数并以任何你想要的方式格式化日期,但我的表单有很多字段,我更愿意将 form.value 发送到我的 api。如果我想使用 moment 的 format 函数,我将不得不遍历每个控件,检查它的类型,获取值并单独格式化,将所有值收集到一个对象中,然后将它发送到我的 api,这是很多额外的编码,以便我可以格式化日期控件。

【问题讨论】:

标签: angular angular-material momentjs


【解决方案1】:

我最终扩展了 moment 对象并覆盖了 toJSON 方法。我还复制和编辑了 MomentDateAdapter,因此它还使用了编辑后的时刻版本,并以 UTC 格式创建了所有内容。

这是瞬间覆盖:

// Depending on whether rollup is used, moment needs to be imported differently.
// Since Moment.js doesn't have a default export, we normally need to import using the `* as`
// syntax. However, rollup creates a synthetic default module and we thus need to import it using
// the `default as` syntax.
import * as _moment from 'moment';
import {default as _rollupMoment} from 'moment';
export class MomentConstructor
{
    static getInstance() {
        const original = _rollupMoment || _moment;
        original.prototype.toJSON = function() {
            return this.format("YYYY-MM-DD");
        }
        return original;
    }
}

//export the typing for Moment so it is easier to import into other classes
export interface Moment extends _moment.Moment {}

对于即时日期适配器,我找到并复制了 Material 提供的适配器并对其进行了编辑,以便即时导入看起来像这样:

import { MomentConstructor, Moment } from './moment-date-only';
const moment = MomentConstructor.getInstance();

我在“moment(”上进行了查找替换,并将其替换为“moment.utc(”。

我在 stackblitz 上构建了一个示例,但就像我在问题中所说的那样,stackblitz 无法正确处理适配器,因此为了使其正常工作,您需要在本地实现它。

【讨论】:

    【解决方案2】:

    您可以使用管道以角度更改日期值格式,首先您需要安装momentjs,实现您的转换管道功能。

    import {Pipe, ChangeDetectorRef, PipeTransform, OnDestroy, NgZone} from '@angular/core';
    import * as moment from 'moment';
    
    // under systemjs, moment is actually exported as the default export, so we account for that
    const momentConstructor: (value?: any) => moment.Moment = (<any>moment).default || moment;
    
    @Pipe({name: 'amTimeAgo', pure: false})
    export class TimeAgoPipe implements PipeTransform, OnDestroy {
      private currentTimer: number;
    
      private lastTime: Number;
      private lastValue: Date | moment.Moment;
      private lastOmitSuffix: boolean;
      private lastText: string;
    
      constructor(private cdRef: ChangeDetectorRef, private ngZone: NgZone) {
      }
    
      transform(value: Date | moment.Moment, omitSuffix?: boolean): string {
        if (this.hasChanged(value, omitSuffix)) {
          this.lastTime = this.getTime(value);
          this.lastValue = value;
          this.lastOmitSuffix = omitSuffix;
          this.removeTimer();
          this.createTimer();
          this.lastText = momentConstructor(value).from(momentConstructor(), omitSuffix);
    
        } else {
          this.createTimer();
        }
    
        return this.lastText;
      }
    
      ngOnDestroy(): void {
        this.removeTimer();
      }
    
    
      private createTimer() {
        if (this.currentTimer) {
          return;
        }
        const momentInstance = momentConstructor(this.lastValue);
    
        const timeToUpdate = this.getSecondsUntilUpdate(momentInstance) * 1000;
        this.currentTimer = this.ngZone.runOutsideAngular(() => {
          if (typeof window !== 'undefined') {
            return window.setTimeout(() => {
              this.lastText = momentConstructor(this.lastValue).from(momentConstructor(), this.lastOmitSuffix);
    
              this.currentTimer = null;
              this.ngZone.run(() => this.cdRef.markForCheck());
            }, timeToUpdate);
          }
        });
      }
    
    
      private removeTimer() {
        if (this.currentTimer) {
          window.clearTimeout(this.currentTimer);
          this.currentTimer = null;
        }
      }
    
      private getSecondsUntilUpdate(momentInstance: moment.Moment) {
        const howOld = Math.abs(momentConstructor().diff(momentInstance, 'minute'));
        if (howOld < 1) {
          return 1;
        } else if (howOld < 60) {
          return 30;
        } else if (howOld < 180) {
          return 300;
        } else {
          return 3600;
        }
      }
    
      private hasChanged(value: Date | moment.Moment, omitSuffix?: boolean) {
        return this.getTime(value) !== this.lastTime || omitSuffix !== this.lastOmitSuffix;
      }
    
      private getTime(value: Date | moment.Moment) {
        if (moment.isDate(value)) {
          return value.getTime();
        } else if (moment.isMoment(value)) {
          return value.valueOf();
        } else {
          return momentConstructor(value).valueOf();
        }
      }
    }
    

    【讨论】:

      【解决方案3】:

      既然你有一个 Moment 约会,也许你可以使用它?只需在执行将要执行的操作之前对其进行转换。类似的东西(我没有很多时间,但这给了你一个想法):

      const myStringDate = moment(this.myDatePickerValue; 'YYYY-MM-DD');
      

      Look at the documentation 找到适合你的!

      【讨论】:

      • 我更喜欢让表单自己处理格式
      • 在这种情况下,您必须为此创建一个自定义指令,在每次更改时更新输入值
      • 我正在使用带有时刻适配器和表单控件的材料日期选择器。日期选择器使用将时刻设置为值的表单控件。它处理更改显示值并将其正确格式化为长日期格式。我无法更改控件的值,否则会影响此功能(据我了解)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-02
      • 2019-12-04
      • 1970-01-01
      • 2020-12-22
      • 2019-03-04
      • 1970-01-01
      相关资源
      最近更新 更多