Components: Custom DateAdapter extend MomentDateAdapter issue

Created on 26 Jan 2018  路  5Comments  路  Source: angular/components

Bug, feature request, or proposal:

Bug/Issue

What is the expected behavior?

I am trying to override the parse function of MomentDateAdapter to make Moment use strict parsing by specifying a boolean for the last argument.

parse(value, parseFormat) {
    if (value && typeof value == 'string') {
      console.log(moment(value, parseFormat, this.locale, true));
      return moment(value, parseFormat, this.locale, true);
    }
    return value ? moment(value).locale(this.locale) : null;
  }

What is the current behavior?

If I type an invalid date in to the date picker eg 'xxx'
Doing a Console log,
In the parse function I am able to get a Moment object with _isValid : false
However from the ngModel it will return me null.

Please advice if this is the intended behaviour.

capture

What are the steps to reproduce?

https://stackblitz.com/edit/angular-qfl1t7?file=app/custom-date-adapter.ts

Key in 'x' into the mat-datepicker
Open the Console
Notice that console.log(moment(value, parseFormat, this.locale, true)); return a Moment object with _isValid : false
Notice that console.log(e); from the ngModel returns null

What is the use-case or motivation for changing an existing behavior?

Able to do a custom validation based on the _isValid property of the Moment object

If _isValid = false there is a use case to throw an "Invalid format" Validation
If it is null, there is a use case to throw an "Required" Validation

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Angular 5.2.2
Material 5.1.0
Chrome Browser

Is there anything else we should know?

NA

Most helpful comment

If it helps further...

1) Cannot make the difference between the required error and the matDatepickerParse error.
Ans: https://stackblitz.com/edit/angular-qfl1t7-mx991y

2) If the field is not toucher the matDatepickerParse is not throw...
Ans: Implement custom ErrorStateMatcher
https://stackblitz.com/edit/angular-qfl1t7-p4zbuj

All 5 comments

Update

I just realised that even though ngModel return as null, it will throw an error matDatepickerParse
I am able to use this to create an custom validation.

I am still not sure if it is correct that ngModel should return null.
Kindly close this issue if the behaviour is as designed.

Thank you

@skyfremen I am missing something because even if I create a custom validator, I cannot make the difference between the required error and the matDatepickerParse error.

And If the field is not toucher the matDatepickerParse is not throw...

@jogelin Sorry for the late reply

You need to create a custom DateAdapter that extend the MomentDateAdapter and make use of the Strict Mode

Below is a copy of my CustomDateAdapter

import { Inject, Injectable, Optional } from '@angular/core';
import { MAT_DATE_LOCALE } from '@angular/material';
import { MomentDateAdapter } from '@angular/material-moment-adapter';
import * as _moment from 'moment';
import { default as _rollupMoment, Moment } from 'moment';

const moment = _rollupMoment || _moment;

@Injectable()
export class UTCDateAdapter extends MomentDateAdapter {

    constructor( @Optional() @Inject(MAT_DATE_LOCALE) dateLocale: string) {
        super(dateLocale);
    }

    parse(value: any, parseFormat: string | string[]): Moment | null {
        if (value && typeof value === 'string') {
            return moment.utc(value, parseFormat, this.locale, true);
        }
        return value ? moment.utc(value).locale(this.locale) : null;
    }

    createDate(year: number, month: number, date: number): Moment {
        // Moment.js will create an invalid date if any of the components are out of bounds, but we
        // explicitly check each case so we can throw more descriptive errors.
        if (month < 0 || month > 11) {
            throw Error(`Invalid month index "${month}". Month index has to be between 0 and 11.`);
        }

        if (date < 1) {
            throw Error(`Invalid date "${date}". Date has to be greater than 0.`);
        }

        let result = moment.utc({ year, month, date }).locale(this.locale);

        // If the result isn't valid, the date must have been out of bounds for this month.
        if (!result.isValid()) {
            throw Error(`Invalid date "${date}" for month with index "${month}".`);
        }

        return result;
    }

    today(): Moment {
        return moment.utc().locale(this.locale);
    }
}

If it helps further...

1) Cannot make the difference between the required error and the matDatepickerParse error.
Ans: https://stackblitz.com/edit/angular-qfl1t7-mx991y

2) If the field is not toucher the matDatepickerParse is not throw...
Ans: Implement custom ErrorStateMatcher
https://stackblitz.com/edit/angular-qfl1t7-p4zbuj

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jelbourn picture jelbourn  路  94Comments

jelbourn picture jelbourn  路  171Comments

vibingopal picture vibingopal  路  80Comments

tyler2cr picture tyler2cr  路  57Comments

kara picture kara  路  94Comments