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

Jer*_*ell 122 javascript data-binding angularjs angularjs-scope

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

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

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

$scope.$watch("property", function (newValue, oldValue) {
    $scope.outputMessage = "oldValue: " + oldValue + " newValue: " + newValue;
    $scope.property = Globalize.parseFloat(newValue);
});
Run Code Online (Sandbox Code Playgroud)

(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);
});
Run Code Online (Sandbox Code Playgroud)

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

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

有没有更简单的方法来使用AngularJS实现这种情况?我错过了文档中的一些功能吗?

pha*_*aas 229

事实证明,这是一个非常优雅的解决方案,但它没有很好的记录.

用于显示的格式化模型值可由|操作员和角度处理formatter.事实证明,ngModel不仅包含格式化程序列表,还包含解析器列表.

1. ng-model用于创建双向数据绑定

<input type="text" ng-model="foo.bar"></input>
Run Code Online (Sandbox Code Playgroud)

2.在角度模块中创建一个指令,该指令将应用于同一个元素,并且取决于ngModel控制器

module.directive('lowercase', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attr, ngModel) {
            ...
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

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

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

function toUser(text) {
    return (text || '').toLowerCase();
}
ngModel.$parsers.push(fromUser);
ngModel.$formatters.push(toUser);
Run Code Online (Sandbox Code Playgroud)

4.将新指令添加到已有的指令中 ngModel

<input type="text" lowercase ng-model="foo.bar"></input>
Run Code Online (Sandbox Code Playgroud)

这是一个工作示例,它将模型中的文本转换为小写,input然后返回大写

模型控制器API文档还有一个简要说明和其他可用方法的概述.

  • 由于"require:'ngModel'",链接函数的第4个参数将是ngModel指令的控制器 - 即foo.bar的控制器,它是[ngModelController]的一个实例(http://docs.angularjs.org/api /ng.directive:ngModel.NgModelController).您可以根据需要命名第4个参数.(我会把它命名为`ngModelCtrl`.) (7认同)
  • http://docs.angularjs.org/guide/forms在"自定义验证"部分中记录了此技术. (7认同)
  • @Mark Rajcok 在提供的小提琴中,在单击“加载数据”时——全部小写,我预计模型值将全部大写,但模型值很小。请问可以吗?解释原因以及如何使模型始终大写 (2认同)
  • @rajkamal,因为 loadData2() 直接修改 `$scope`,所以模型将被设置为......直到用户与文本框交互。此时,任何解析器都可以影响模型值。除了解析器之外,您还可以向控制器添加 $watch 来转换模型值。 (2认同)