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'};
});
Complete example that formats numbers, inserting spaces every 3 characters, starting from the end:
'use strict'
String::reverse = ->
@split('').reverse().join('')
app = angular.module('app', [])
app.directive 'intersperse', ->
require: 'ngModel'
link: (scope, element, attrs, modelCtrl) ->
modelCtrl.$formatters.push (input) ->
return unless input?
input = input.toString()
input.reverse().replace(/(.{3})/g, '$1 ').reverse()
modelCtrl.$parsers.push (input) ->
return unless input?
input.replace(/\s/g, '')
Usage:
<input ng-model="price" intersperse/>
Plunkr example: http://plnkr.co/edit/qo0h9z
You wouldn't need to create a new filter from zero, since angular has already a built-in filter for date types. http://docs.angularjs.org/api/ng.filter:date
I believe that's exactly what you need.