59

Angular material introduced a new date picker component found here.

I want the date returned by this component to be in the format yyy-mm-dd but I am not sure how is this done. By searching I found that $mdDateLocaleProvider can be used, but I could not find an example of using it.

Can someone show me a working example of formatting the date returned by md-datepicker?

mruanova
  • 6,351
  • 6
  • 37
  • 55
dearn44
  • 3,198
  • 4
  • 30
  • 63

13 Answers13

97

There is a documentation for $mdDateLocaleProvider in the Angular Material docs.

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

If you don't use moment.js, substitute the code inside formatDate for whatever you wish to use to format the date.

Here is a CodePen example based on the samples from Angular Material docs.

Alexandre Bourlier
  • 3,972
  • 4
  • 44
  • 76
Bohuslav Burghardt
  • 33,626
  • 7
  • 114
  • 109
  • This sets today's date to datepicker. I want it to be null on load. What should I do? – Ali Demirci Oct 16 '15 at 16:30
  • 5
    @AliDemirci Assuming that the date you are binding to is `undefined` on load, something like this should work: `return date ? moment(date).format('YYYY-MM-DD') : '';` – Bohuslav Burghardt Oct 16 '15 at 16:55
  • 4
    thank you that works for input but it does not return me the formatted date on ng-model instead it gives me a date like `Tue Oct 06 2015 00:00:00 GMT+0300` – Ali Demirci Oct 19 '15 at 08:15
  • 3
    Unfortunately it doesn't work if the date is typed from the keyboard. Eg. for the above format I'm typing 2016-04-01 which returns 4th January :/ – kazuar Jan 04 '16 at 13:38
  • @BohuslavBurghardt I still get the the value of `MyDate` variable as "2016-01-08T16:07:31.352Z" see in http://codepen.io/anon/pen/OMmjaP – Saurabh Jan 08 '16 at 16:08
  • @saurabh: I have the same issue, have you find out a way to fix it yet? – loveNZ Feb 09 '16 at 22:58
  • @loveNZ Couldn't exactly fix it, I was trying to save it in Backend system, Did some other workaround there. What is your exact use-case for which you need it? – Saurabh Feb 11 '16 at 16:22
  • 1
    @saurabh, I have fixed it. my use-case is simply to send this date value back to the server, but our java-backend couldn't process it. so my backend dev asked me to send the date back without the ".***Z". And fortunately moment(question.date).format('YYYY-MM-DDTHH:mm:ss') did the trick for me. hope this helps – loveNZ Feb 12 '16 at 03:39
  • @loveNZ Note that removing the timezone ("Z" means UTC) can lead to errors with DST. As you're sending an UTC date, if server does not explicitly parse it as UTC but in local timezone you could get an offset of one day. You should have replace the last 'Z' with '+0000' to preserve timezone and make it easily parseable in java. – Ludovic Ronsin Jun 04 '16 at 00:39
62

To also address the problem pointed out by kazuar:

Unfortunately it doesn't work if the date is typed from the keyboard

you should define the parseDate method as well. From the docs:

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

For a full example, I have in my app (using moment):

$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);
};

Regards

shulito
  • 796
  • 5
  • 13
  • This should probably be the accepted answer. If you're using moment, you'll also need to add it to your config params after $mdDateLocaleProvider as so: `angular.module('app') .config(function ($mdDateLocaleProvider, moment) { ... })` – yjimk Oct 13 '16 at 21:45
  • While this code gets called, it doesn't seem to actually update the value. – mcv Dec 06 '16 at 14:27
22

For those not using Moment.js, you can format as a string:

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

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

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

  };
});
Ben Taliadoros
  • 7,003
  • 15
  • 60
  • 97
8

Worked perfectly when the date is typed from the keyborard and returned null in initiation to avoid the massage 'Invalid date' in md-datapicker directive:

$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);
};
Janderson Silva
  • 1,787
  • 17
  • 14
  • Does this need something extra? I tried it (without moment, though), and the code does get called, but the result doesn't end up in the model. – mcv Dec 06 '16 at 14:45
  • I got this working without moment.js. In the component that uses it (rather than at config stage) I do: `$mdDateLocale.formatDate = date => $filter('date')(date, "mediumDate");` The other direction is automatically handled by javascript's built in date parsing, which is extremely forgiving. – mcv Dec 18 '16 at 07:57
5

-- When we use md-DatePicker in md-dialog then $mdDateLocaleProvider service doesnot format the date as we need. We have to use $mdDateLocale in controller of md-dialog to format the date of md-DatePicker. for example -

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();
});
Ravindra Vairagi
  • 1,055
  • 15
  • 22
5

Changing date format, month names and week names during runtime is perfectly possible with AngularJS 1.5.9 and moment 2.17.1.

First configure the initial language. (In this example the configuration of angular-translate/$translateProvider is optional.)

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') : '';
  };
}

Later you may have some base controller that watches a language variable which is changed when the user selects another language.

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;
  });
}

Notice how we don't need to change the $mdDateLocale.formatDate and $mdDateLocale.parseDate methods as they are already configured to use the 'L'-format that is changed by calling moment.locale(newValue).

See the documentation for $mdDateLocaleProvider for more locale customization: https://material.angularjs.org/latest/api/service/$mdDateLocaleProvider

Bonus: This is how the language selector may look like:

<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>
Christiaan Westerbeek
  • 10,619
  • 13
  • 64
  • 89
3

Using $filter instead of moment.js and in reference to responses from @Ian Poston Framer and @java dev for me the following finally worked for me:

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

I couldn't inject $filter into.config because it's not a provider, so I had to do it inside .run with $mdDateLocale.

marcinowski
  • 349
  • 2
  • 4
3

I had same problem and came up with this simple solution with the help of moment.js. I used ng-change attribute which fires when the date is changed.

Inside your HTML:

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

Inside your controller:

$scope.dateChanged = function() {
    this.myDate = moment(this.myDate).format('YYYY/MM/DD');
}
ttvd94
  • 307
  • 3
  • 13
2

For angular-material >= 5.x.x

The recommended way of using other custom/predefined date formats is described in the angular material documentation:

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

An implementation example using MomentJS for customizing and parsing datetime display 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}
    ]
})

...

Depending on your implementation, inside the component you might also need to use:

date = new FormControl(moment());

You must also install Moment library and adapter for Angular:

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

Alex P.
  • 1,140
  • 13
  • 27
1

I'd like to provide my solution that's 100% based off of Christiaan Westerbeek's post. I really like what he did, but I personally wanted something a bit more simplistic.

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;

}]);

some service file that deals with localization/translations/etc

// 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;

};

It should be noted that this solution will not live re-format your md-datepicker's display values. It will only work when the model changes values.

0

If you are using the latest version of angular-material.js then use the $mdDateLocale service. This code sample uses angular's built in date filter as an alternative to using the moment.js library. See other date format options using angular's $filter service here at this link https://docs.angularjs.org/api/ng/filter/date.

// 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");
  };

});
Ian Poston Framer
  • 938
  • 12
  • 16
0

I used $mdDateLocaleProvider to format it on the frond end. If you want to format date while sending it to the back end, the following worked for me :-

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

I have the above in controller.

Jason Roman
  • 8,146
  • 10
  • 35
  • 40
java dev
  • 1
  • 1
0

in my case I was loosing the PlaceHolder everythig works but the placeHolder was disappearing when I use custom formatting. Below lines solved my problem with placeholder.

$mdDateLocaleProvider.formatDate = function (date) {
                if(date==null)
                return "";
                var m = moment(date);
                return m.isValid() ? m.format('L') : '';
            };
katmanco
  • 1,146
  • 12
  • 24