Using Pikaday with Angular Formly

21st December 2015

Pikaday is a great little date selector plugin. Whilst the Pikaday Angular plugin makes it easy to integrate into an Angular application, there's slightly more work involved in getting it working with Angular Formly.

If you haven't used Formly, it's essentially a framework for creating forms declaratively; rather than writing out its HTML by hand. It takes care of rendering the relevant controls and their labels, enables you to attach validation and it will inject error messages for you, and a number of other features.

The problem with using Pikaday with Formly is that you're probably going to want to translate the display value of the plugin into a format more suitable for storage. For example in one form you might display "12 January 2016" but want it bound to a model in ISO 6031 format.

This is achieved by attaching a lightweight controller to the form element which monitors the plugin for changes, then sets the underlying model accordingly. Additionally it sets the initial value if required.

Note that you still need Pikaday Angular:

bower install --save pikaday-angular

Now you can create a new Formly type by placing the following code in, for example, your application's run() section:

formlyConfig.setType({
  name: 'pikaday',
  template: '<input class="form-control" pikaday="theDate" on-select="select(pikaday)" />',        
  link: function($scope, el, attrs, ctrl) {
    // Set the initial value
    var value = $scope.model[$scope.options.key];          
    $scope.$$childHead.pikaday.setDate( new Date(value) );          
  },
  controller: ['$scope', function ($scope) {          
    $scope.select = function( pikaday ) {
      // Set the relevant property on the model
      $scope.model[$scope.options.key] = pikaday.getDate().toISOString();            
    }
  }],
  wrapper: ['bootstrapLabel', 'bootstrapHasError']
});

You'll probably want to adapt certain parts according to your preferences; for example, this is Bootstrap flavoured, as you can see from the class name (form-control) and the addition of Bootstrap-specific element wrappers. You may also wish to choose an alternative format for the underlying value; I'm using toISOString(), but you might prefer a UNIX timestamp, for example.