如何在 AngularJS 中进行双向过滤?

Posted

技术标签:

【中文标题】如何在 AngularJS 中进行双向过滤?【英文标题】:How to do two-way filtering in AngularJS? 【发布时间】:2012-07-21 22:20:51 【问题描述】:

AngularJS 可以做的一件有趣的事情是将过滤器应用于特定的数据绑定表达式,这是一种方便的应用方式,例如,模型属性的文化特定货币或日期格式。在范围上具有计算属性也很好。问题是这些特性都不适用于双向数据绑定方案——从范围到视图只有单向数据绑定。这似乎是一个优秀图书馆的明显遗漏 - 还是我错过了什么?

在KnockoutJS 中,我可以创建一个读/写计算属性,它允许我指定一对函数,一个被调用以获取属性的值,一个在设置属性时被调用.例如,这使我能够实现文化感知输入 - 让用户键入“$1.24”并将其解析为 ViewModel 中的浮点数,并在输入中反映 ViewModel 中的更改。

我能找到与此类似的最接近的事情是使用$scope.$watch(propertyName, functionOrNGExpression); 这允许我在$scope 中的属性更改时调用一个函数。但这并不能解决例如文化感知输入问题。请注意当我尝试在 $watch 方法本身中修改 $watched 属性时出现的问题:

$scope.$watch("property", function (newValue, oldValue) 
    $scope.outputMessage = "oldValue: " + oldValue + " newValue: " + newValue;
    $scope.property = Globalize.parseFloat(newValue);
);

(http://jsfiddle.net/gyZH8/2/)

当用户开始输入时,输入元素会变得非常混乱。我通过将属性拆分为两个属性来改进它,一个用于未解析的值,一个用于解析的值:

$scope.visibleProperty= 0.0;
$scope.hiddenProperty = 0.0;
$scope.$watch("visibleProperty", function (newValue, oldValue) 
    $scope.outputMessage = "oldValue: " + oldValue + " newValue: " + newValue;
    $scope.hiddenProperty = Globalize.parseFloat(newValue);
);

(http://jsfiddle.net/XkPNv/1/)

这是对第一个版本的改进,但有点冗长,请注意仍然存在范围更改的 parsedValue 属性的问题(在第二个输入中键入一些内容,这会更改 @987654331直接@。注意顶部输入不会更新)。这可能发生在控制器操作或从数据服务加载数据时。

有没有更简单的方法来使用 AngularJS 来实现这个场景?我是否缺少文档中的某些功能?

【问题讨论】:

【参考方案1】:

事实证明,有一个非常优雅的解决方案,但没有很好的文档记录。

可通过| 运算符和角度formatter 处理显示模型值的格式。原来ngModel不仅有格式化器列表,还有解析器列表。

1。使用ng-model 创建双向数据绑定

<input type="text" ng-model="foo.bar"></input>

2。在您的 Angular 模块中创建一个指令,该指令将应用于相同的元素,并且取决于 ngModel 控制器

module.directive('lowercase', function() 
    return 
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attr, ngModel) 
            ...
        
    ;
);

3。在link 方法中,将您的自定义转换器添加到ngModel 控制器

function fromUser(text) 
    return (text || '').toUpperCase();


function toUser(text) 
    return (text || '').toLowerCase();

ngModel.$parsers.push(fromUser);
ngModel.$formatters.push(toUser);

4。将您的新指令添加到已具有 ngModel 的同一元素中

<input type="text" lowercase ng-model="foo.bar"></input>

这是一个working example,它将input中的文本转换为小写,然后在模型中转换回大写

模型控制器的 API 文档也有一个简短的解释和其他可用方法的概述。

【讨论】:

您是否有任何理由使用“ngModel”作为链接函数中第四个参数的名称?这不只是指令的通用控制器,基本上与 ngModel 属性无关吗? (这里还在学习角度,所以我可能完全错了。) 因为“require: 'ngModel'”,链接函数的第四个参数将是ngModel指令的控制器——即foo.bar的控制器,它是ngModelController的一个实例。您可以随意命名第 4 个参数。 (我将其命名为ngModelCtrl。) 此技术记录在 docs.angularjs.org/guide/forms 的自定义验证部分。 @Mark Rajcok 在提供的小提琴中,同时单击加载数据 - 全部小写,我预计模型值将全部大写,但模型值很小。你能请。解释为什么,以及如何使模型总是大写 @rajkamal,因为 loadData2() 直接修改了$scope,这就是模型将被设置为......直到用户与文本框交互。那时,任何解析器都可以影响模型值。除了解析器之外,您还可以在控制器中添加一个 $watch 来转换模型值。

以上是关于如何在 AngularJS 中进行双向过滤?的主要内容,如果未能解决你的问题,请参考以下文章

如何在嵌套的Json中使用angularjs进行过滤

如何利用AngularJs快速搭建前端基本框架

如何在 ngClass 中使用 AngularJS 过滤器?

AngularJS数据双向绑定

如何在AngularJS中使用过滤器从数组中删除项目?

如何使用AngularJS对表单提交内容进行验证