The custom native date adapter is facing compatibility issues following the upgrade of Angular/Material from version 5 to 6

In my Angular 5 application, I had implemented a custom date adapter as follows:

import {NativeDateAdapter} from "@angular/material";
import {Injectable} from "@angular/core";

@Injectable()
export class CustomDateAdapter extends NativeDateAdapter {

    parse(value: any): Date | null {
        if ((typeof value === 'string') && (value.indexOf('/') > -1)) {
            const str = value.split('/');
            return new Date(Number(str[2]), Number(str[1])-1, Number(str[0]), 12);
        }
        const timestamp = typeof value === 'number' ? value : Date.parse(value);
        return isNaN(timestamp) ? null : new Date(timestamp);
    }

    format(date: Date, displayFormat: Object): string {
        return date.getFullYear() + "-" + (date.getMonth() + 1).toString().padStart(2, '0') + "-" + date.getDate().toString().padStart(2, '0');
    }

}

This custom date adapter was defined in app.module.ts.

@NgModule({
    imports: [...],
    declarations: [...],
    providers: [
        ...,
        { provide: DateAdapter, useClass: CustomDateAdapter }
    ],
    bootstrap: [
        AppComponent
    ]
})
export class AppModule {}

However, after upgrading to Angular/Material version 6, the custom date adapter stopped working and an error started occurring. The error message is:

ERROR TypeError: Cannot read property 'TRIDENT' of undefined
    at new NativeDateAdapter (native-date-adapter.ts:83)
    at new CustomDateAdapter (custom.date.adapter.ts:5)
    at _createClass (ng_module.ts:171)
    at _createProviderInstance$1 (ng_module.ts:143)
    at resolveNgModuleDep (ng_module.ts:104)
    at NgModuleRef_.get (refs.ts:502)
    at resolveDep (provider.ts:416)
    at createClass (provider.ts:276)
    at createDirectiveInstance (provider.ts:135)
    at createViewNodes (view.ts:303)

I found a solution on Stack Overflow where it was suggested to add a constructor:

constructor(matDateLocale: string) {
    super(matDateLocale, new Platform());
}

After adding this constructor, a new error occurred:

ERROR Error: StaticInjectorError(AppModule)[DateAdapter -> String]: 
  StaticInjectorError(Platform: core)[DateAdapter -> String]: 
    NullInjectorError: No provider for String!
    at NullInjector.get (injector.ts:35)
    at resolveToken (injector.ts:332)
    at tryResolveToken (injector.ts:274)
    at StaticInjector.get (injector.ts:154)
    at resolveToken (injector.ts:332)
    at tryResolveToken (injector.ts:274)
    at StaticInjector.get (injector.ts:154)
    at resolveNgModuleDep (ng_module.ts:124)
    at _createClass (ng_module.ts:173)
    at _createProviderInstance$1 (ng_module.ts:143)

At this point, I am seeking suggestions on how to resolve this issue and make the custom date adapter work again.

Answer №1

I successfully resolved the issue by implementing the MomentDateAdapter along with a customized date format.

import {NgModule} from "@angular/core";
import {AppComponent} from "./app.component";
import {DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE} from "@angular/material";
import {MomentModule} from "ngx-moment";
import {MomentDateAdapter} from '@angular/material-moment-adapter';

export const ISO_FORMAT = {
    parse: {
        dateInput: 'LL',
    },
    display: {
        dateInput: 'YYYY-MM-DD',
        monthYearLabel: 'MMM YYYY',
        dateA11yLabel: 'LL',
        monthYearA11yLabel: 'MMMM YYYY',
    },
};

@NgModule({
    imports: [
        MomentModule,
        ...
    ],
    declarations: [
        AppComponent,
        ...
    ],
    providers: [
        {provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE]},
        {provide: MAT_DATE_FORMATS, useValue: ISO_FORMAT},
        ...
    ],
    bootstrap: [
        AppComponent
    ]
})

export class AppModule {}

Answer №2

Make sure not to rely on moment and instead refer to the official documentation.

Here is a straightforward example of using a customized date adapter.

Customized date adapter:

import { Platform } from '@angular/cdk/platform';
import { DatePipe } from '@angular/common';
import { Inject, Injectable, Optional } from '@angular/core';
import { MAT_DATE_LOCALE, NativeDateAdapter } from '@angular/material/core';

@Injectable()
export class CustomDateAdapter extends NativeDateAdapter {
  constructor(@Optional() @Inject(MAT_DATE_LOCALE) matDateLocale: string, platform: Platform) {
    super(matDateLocale, platform);
  }

  format(date: Date): string {
    // implement custom logic here
    return new DatePipe(this.locale).transform(date, 'MMMM YYYY');
  }
}

How to use in your component:

import { Platform } from '@angular/cdk/platform';
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { FormControl } from '@angular/forms';
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core';
import { MatDatepicker } from '@angular/material/datepicker';
import { CustomDateAdapter } from './CustomDateAdapter';

export const MY_FORMATS = {
  parse: {
    dateInput: 'MMMM YYYY',
  },
  display: {
    dateInput: 'MMMM YYYY',
    monthYearLabel: 'MMM YYYY',
    dateA11yLabel: 'LL',
    monthYearA11yLabel: 'MMMM YYYY',
  },
};

@Component({
  selector: 'app-month-picker',
  templateUrl: './month-picker.component.html',
  styleUrls: ['./month-picker.component.scss'],
  providers: [
    {
      provide: DateAdapter,
      useClass: CustomDateAdapter,
      deps: [MAT_DATE_LOCALE, Platform],
    },
    { provide: MAT_DATE_FORMATS, useValue: MY_FORMATS },
  ],
})
export class YourComponent

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Customizable JSX Attributes for Your TSX/JSX Application

Currently, I am in the process of converting my React project from JavaScript to TypeScript. One challenge I encountered is that TSX React assumes all properties defined in a functional component are mandatory props. // ComponentA.tsx class ComponentA ext ...

Exploring Angular 2 on Apache: A Guide to Optimizing for Search Engine

After creating a basic Angular 2 app and hosting it on an Apache server, I'm unsure if search engines will crawl my site. I read that the site must be rendered server side but couldn't find more information about it online. ...

Can one invoke ConfirmationService from a different Service?

How can I declare an application-wide PrimeNG dialog and display it by calling ConfirmationService.confirm() from another service? Below is the HTML code in app.component.html: <p-confirmDialog [key]="mainDialog" class="styleDialog" ...

Angular application automatically adding 'localhost' before the backend API endpoint

After migrating my backend to AWS, the backend URL is functioning correctly in Postman. However, when I use the backend URL in an Angular service, 'localhost' is being added to the front of it. How can I resolve this issue? Backend URL: api.an ...

NextRouter does not have a property called "refresh"

Here is the provided code snippet: "use client"; import { useRouter } from "next/router"; import { useState } from "react"; export default function CreatePrompt() { const [title, setTitle] = useState(""); const ...

Why does using `withCredentials: true` and including a `body` in the request cause a CORS error in Angular HttpClient?

My objective is to make a request to a Cloud Function, receive a response with a Set-Cookie header, and have the browser store the cookie. The issue arises when the response containing a Set-Cookie header is ignored without the presence of withCredentials ...

Angular 9 - Button unable to be clicked under certain conditions

I have a webpage that contains a lot of information, and I would like to make it easier for the user to show/hide specific parts by clicking on buttons. Check out this stackblitz to see what I've done. Here's a brief summary of the code: <but ...

ESLint encountered an issue: Reserved keyword 'interface' triggered a parsing error

Whenever I utilize the most recent version of eslint to initiate a project, a specific error pops up: import { ref } from 'vue' defineProps<{msg: string}>() const count = ref(0) Error message: Unexpected token )eslint Adjusting the code ...

Declaring types in NGRX Effect V10 has changed since classes are no longer used, causing types to not be inferred as easily

After the V10 upgrade to NGRX, there seems to be a change where passing a type of Action to the effect is no longer possible. As Actions are now declared as functions instead of classes, I'm wondering if there's still a way to handle this in V10? ...

Generating PDF files from HTML using Angular 6

I am trying to export a PDF from an HTML in Angular 6 using the jspdf library. However, I am facing limitations when it comes to styling such as color and background color. Is there any other free library besides jspdf that I can use to achieve this? Feel ...

Failure to trigger the callback for mongoose.connection.once('open') event

Currently, I am in the process of setting up a custom Node server using Next.js. Although I'm utilizing Next.js this time around, it should not affect the outcome. In my previous applications, I always relied on mongoose.connection.once('open&ap ...

Error: Peer Dependency Not Fulfilled

Warning: The package @schematics/[email protected] has a peer dependency of @angular-devkit/[email protected], but it is not installed. You will need to handle the peer dependencies manually. I initially installed Angular CLI using npm instal ...

Is your React Native list elements feeling a little too close for comfort?

I'm facing an issue where the items in my list are not properly spaced out and I'm unable to figure out why. I have 3 elements for each letter that should be separated from each other. I suspect that the issue might be related to the fact that th ...

What are the steps to integrate an in-memory cache in an Angular frontend using GraphQL queries?

In our Angular frontend application, we are utilizing GraphQL queries with Apollo Client to fetch data. We are interested in implementing caching for our data retrieval process. Initially, we will query the data and store it in the cache. Subsequent requ ...

Error 404: Angular 2 reports a "Not Found" for the requested URL

I am currently in the process of integrating an Angular 2 application with a Java Spring Boot backend. As of now, I have placed my Angular 2 files under src/main/resources/static (which means that both the Angular and Spring apps are running within the sam ...

Unable to serve static files when using NextJs in conjunction with Storybook

The documentation for Next.js (found here) suggests placing image file paths under the public directory. I have a component that successfully displays an image in my Next.js project, but it doesn't render properly within Storybook. The image file is ...

Managing errors with Angular2 Observables within the HTML template

The updated Angular's use of observables is a game-changer. No more long chains of .done().fail().always() like in JQuery - NG2 simplifies it all with the | async pipe. However, what happens if something goes wrong while loading data for myObservable? ...

Ways to access a property within an object using TypeScript

Can you help me extract the "attributes" array from this object and store it in a new variable? obj = { "_id": "5bf7e1be80c05307d06423c2", "agentId": "awais", "attributes": [ // that array. { "created ...

Excluding specific parameter values in Angular Route configuration---Is it possible to exclude certain parameter values

I've set up my route like this const routes: Routes = [ { path: ':id', component: PickUpWrapperComponent, resolve: { request: PickupRequestResolverService }, children: [ { path: '', component ...

What is the reason behind Angular triggering @HostListener as soon as the element begins to appear in the DOM?

I encountered an issue while writing a directive to close an element when a user clicks outside of the host element. The problem seems to be that the @HostListener is triggered immediately once the element is displayed in the DOM. It might not actually be ...