在输入元素中使用angularjs过滤器


74

我希望我不会错过doco中任何明显的内容,如果可以的话,我相信有人会帮助您。

我正在使用asp.net webapi返回带有日期字段的DTO。这些使用JSON.Net(格式为'2013-03-11T12:37:38.693')进行序列化。

我想使用过滤器,但是在INPUT元素中,这是否可行?或者我应该创建一个新的过滤器或指令来实现此目的?

// 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'}}

我缺少任何捷径吗?

Answers:


131

简而言之:如果您希望数据在视图和模型中具有不同的表示形式,则需要一个指令,您可以将其视为双向过滤器

您的指令看起来像

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

这是一个有效的jsFiddle示例。


5
看起来不错,但是您将如何应用呢?具体来说,如何指定用于格式设置的过滤器?
保罗·泰勒

@PaulTaylor该指令限制在“属性”而已,并使用该属性在输入栏上(类似于你怎么写<input ng-model="foo">
阿迪亚MP

另外,请查看此答案以获取更完整的示例。
Aditya MP

在JSFiddle上的工作示例?
ViniciusPires 2014年

谢谢!对于我的解决方案,您的示例唯一缺少的是观察模型中的更改并重新运行格式化程序。我不明白如何使用AngularJS轻松实现这一目标,我不得不强制进行元素更新:scope.$watch(attrs.ngModel, function(value){ element.val( $filter('number')(value, 0) ); });
ViniciusPires 2014年

20

在输入字段和模型中具有不同的值与ng-model的本质背道而驰。因此,我建议您采用最简单的方法,并在控制器内应用过滤器,对格式化日期使用单独的变量,并使用观察程序来使格式化日期和原始日期保持同步:

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

});

6
我相信创建一个新的指令来满足要求是一种更清洁的解决方案。如果我正确理解了OP的问题。
全息原理

你是对的。比较干净。我只是想给@leon一个选项,以防他/她还不太习惯自定义指令。
Stewie 2013年

谢谢大家,两个答案都值得赞赏,因为学习替代方法非常好。
2013年

3
-1,两个变量+观看是一个支持地狱。想象一下具有数十个变量的范围(保险计算器等)
Valentin Vasilyev 2013年

16

如果您的输入仅显示数据

如果您实际上只需要输入即可显示一些信息,而正是其他一些元素更改了Angular模型,则可以进行更轻松的更改。

除了编写新的指令外,不要使用ng-model而要使用good,old value

所以代替:

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

这样可以:

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

并且像魅力一样工作:)


3

完整的示例,它格式化数字,从末尾开始每3个字符插入一个空格:

'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, '')

用法:

<input ng-model="price" intersperse/>

Plunkr示例:http ://plnkr.co/edit/qo0h9z


modelCtrl。$ parsers(或formatters).push到底做什么?
文森特

1
@Vincent,它向格式化程序数组添加了一个函数,当需要显示模型值时会调用该函数。可以将$ formatters数组视为一个充满函数的管道,在其中调用每个函数并将结果进一步传递给管道。调用所有功能后,将显示最终结果。$ parsers是类似的事情,但用于编写模型。
Valentin Vasilyev 2013年

我认为这实际上不起作用,您是否有塞子或类似的东西?
mattcole13 2013年

1
真好!唯一的问题是,它会在长度为3的任意倍数的数字之前添加一个空格,而正确的方法是仅在长度为3的倍数且在其后有另一个数字的情况下才添加空格。当您的语言环境未将数字分隔符定义为点(.)时,这看起来并不像问题,它看起来像这样:.999.999
ViniciusPires 2014年

PS .:使用$filter('number');似乎是一种更好的方法,它通过$locale服务加载格式,并且您可以new RegExp("\\"+$locale.NUMBER_FORMATS.GROUP_SEP, 'g');用来将值反转为模型...
ViniciusPires 2014年

0

Angular具有内置的日期格式功能,但是要将其应用于最终想要获取原始(未格式化)日期的输入,您需要创建一个自定义指令

指令示例:

(function () {
    'use strict';

    angular.module('myApp').directive('utcDate', ['$filter', function ($filter) {
        return {
            restrict: 'A', //restricting to (A)ttributes
            require: 'ngModel',
            link: function (scope, elem, attrs, model) {
                if (!model) return;

                var format = 'MM/dd/yyyy h:mm:ss a';
                var timezone = 'UTC';

                //format the date for display
                model.$formatters.push(function (value) {
                    //using built-in date filter
                    return $filter('date')(value, format, timezone);
                });

                //remove formatting to get raw date value
                model.$parsers.push(function (value) {
                    var date = Date.parse(value);
                    return !isNaN(date) ? new Date(date) : undefined;
                });
            }
        };
    }]);
})();

然后应用它:

<input type="text" ng-model="$ctrl.DateField" utc-date />

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.