Using angularjs filter in input element

I hope I haven't missed anything obvious in the doco, if I have I'm sure someone will help.

I'm using asp.net webapi to return a DTO, with date fields. These are serialized using JSON.Net (in format '2013-03-11T12:37:38.693').

I'd like to use a filter but in an INPUT element, is this possible or should I create a new filter or directive to accomplish this?

// this just displays the text value
<input ui-datetime type="text" data-ng-model="entity.date" /> 
// this doesn't work at all
<input ui-datetime type="text" data-ng-model="{{entity.date|date:'dd/MM/yyyy HH:mm:ss a'}}" /> 
// this works fine
{{entity.date|date:'dd/MM/yyyy HH:mm:ss a'}}

Is there any shortcut I'm missing?


In short: if you want your data to have a different representation in the view and in the model, you will need a directive, which you can think of as a two-way filter.

Your directive would look something like

angular.module('myApp').directive('myDirective', function() {
  return {
    require: 'ngModel',
    link: function(scope, element, attrs, ngModelController) {
      ngModelController.$parsers.push(function(data) {
        //convert data from view format to model format
        return data; //converted
      });

      ngModelController.$formatters.push(function(data) {
        //convert data from model format to view format
        return data; //converted
      });
    }
  }
});

HTML:

<input my-directive type="text" data-ng-model="entity.date" /> 

Here is a working jsFiddle example.


Having different values in your input field and in your model goes against the very nature of ng-model. So I suggest you take the simplest approach and apply your filter inside the controller, using a separate variable for formatted date, and employing watchers to keep formatted and original dates in sync:

HTML:

<input ui-datetime type="text" data-ng-model="formattedDate" />

JS:

app.controller('AppController', function($scope, $filter){

  $scope.$watch('entity.date', function(unformattedDate){
    $scope.formattedDate = $filter('date')(unformattedDate, 'dd/MM/yyyy HH:mm:ss a');
  });

  $scope.$watch('formattedDate', function(formattedDate){
    $scope.entity.date = $filter('date')(formattedDate, 'yyy/MM/dd');
  });

  $scope.entity = {date: '2012/12/28'};

});

If your input only displays data

If you actually need an input to simply display some information and it is some other element that changes the Angular model you can make an easier change.

Instead of writing new directive simply DO NOT USE the ng-model and use good, old value.

So instead of:

<input data-ng-model={{entity.date|date:'dd/MM/yyyy HH:mm:ss'}}" /> 

This will do:

<input value="{{entity.date|date:'dd/MM/yyyy HH:mm:ss'}}" /> 

And works like a charm :)