Data binding 以AngularJS为单位的华氏温度和摄氏温度双向转换

Data binding 以AngularJS为单位的华氏温度和摄氏温度双向转换,data-binding,angularjs,Data Binding,Angularjs,在AngularJS中,如何$watch一个$scope变量并使用它更新另一个变量是很简单的。但是,如果两个范围变量需要相互监视,那么最佳实践是什么 我举了一个双向转换器为例,它可以将华氏温度转换为摄氏温度,反之亦然。如果您在华氏温度中键入“1”,它可以正常工作,但请尝试“1.1”,Angular将在覆盖刚输入的稍有不同的值(1.10000000000014)之前反弹一点: 这里有一个小插曲: 有哪些不同的方法可以阻止Angular“跳跃”并强制它使用您键入的值,例如使用格式化程序或解析器(或任

在AngularJS中,如何$watch一个$scope变量并使用它更新另一个变量是很简单的。但是,如果两个范围变量需要相互监视,那么最佳实践是什么

我举了一个双向转换器为例,它可以将华氏温度转换为摄氏温度,反之亦然。如果您在华氏温度中键入“1”,它可以正常工作,但请尝试“1.1”,Angular将在覆盖刚输入的稍有不同的值(1.10000000000014)之前反弹一点:

这里有一个小插曲:


有哪些不同的方法可以阻止Angular“跳跃”并强制它使用您键入的值,例如使用格式化程序或解析器(或任何其他技巧)?

我认为最简单、最快、最正确的解决方案是使用一个标记跟踪正在编辑的字段,并且只允许从该字段进行更新

您只需使用
ng change
指令在正在编辑的字段上设置标志

必要的代码更改:

将控制器修改为如下所示:

函数温度转换器trl($scope){
//跟踪上次编辑的用户
$scope.edited=null;
$scope.markEdited=函数(哪个){
$scope.edited=which;
};
//仅在修改正确的字段时进行编辑
$scope.$watch('fahrenheit',函数(值){
如果($scope.edited=='F'){
$scope.cercil=(值-32)*5.0/9.0;
}
});
$scope.$watch('摄氏度'),函数(值){
如果($scope.edited=='C'){
$scope.fahrenheit=值*9.0/5.0+32;
}
});
}
然后将此简单指令添加到输入字段(根据需要使用
F
C
):


这是一个非常好的问题,我正在回答它,尽管它已经被接受:)

在Angular中,$范围就是模型。模型是一个存储数据的地方,您可能希望在应用程序的其他部分中保存或使用数据,因此,它应该使用良好的模式进行设计,就像在数据库中一样

您的模型有两个冗余的温度场,这不是一个好主意。哪一个是“真实”温度?有时,为了提高访问效率,您需要对模型进行非规范化,但这实际上只是当值是幂等值时的一种选择,正如您所发现的,这并不是由于浮点精度造成的

如果你想继续使用这个模型,它看起来会像这样。您可以选择其中一个作为“真实源”温度,然后将另一个输入作为带有格式化程序和解析器的方便输入框。假设模型中需要华氏温度:

<input type="number" ng-model="temperatureF">
<input type="number" ng-model="temperatureF" fahrenheit-to-celcius>
这样,您就可以避免“跳转”,因为$parser只在用户操作上运行,而不在模型更改上运行。你仍然有很长的小数,但这可以通过四舍五入来弥补

然而,在我看来,你不应该用模型来做这个。如果您只想“每个盒子更新另一个盒子”,那么您可以完全做到这一点,甚至不需要模型。这假设输入框一开始是空白的,它只是用户转换温度的一个简单工具。如果是这样的话,你没有模型,没有控制器,甚至根本不使用角度。在这一点上,它是一个纯粹基于视图的小部件,基本上只是jQuery或jQLite。不过,它的用处有限,因为没有模型,它在角度上不会影响其他任何东西

要做到这一点,您可以创建一个
temperatureConverter
指令,该指令有一个带有两个输入框的模板,并监视两个框并设置它们的值。比如:

fahrenheitBox.bind('change', function() {
  celciusBox.val((Number(fahrenheitBox.val()) - 32) * 5.0 / 9.0);
});

如果有人认为我在底部的无关便条不合适,我会删除它。请告诉我。谢谢,你的回答太好了。我很快就把你多余的笔记记下来了,非常感激。我将编辑我的问题以删除(或改写)额外需求。太棒了,很高兴你没有被冒犯!:-)现在我自己把那一块剥掉。那一块伤了我的头。递归。。。改变它+1我只是想在睡觉前喝一杯。啊!这是一个好问题的原因是因为这种情况有无限的循环-如果计算不是彼此相反+1.我会惊讶地看到任何其他不同的答案。由于我有DSP的背景,我很难不去研究这个问题的数学,所以我就放弃了:这个问题有可能进入无限循环(除了Angular有一个最大迭代的内置限制)。下面是一个很好的解释,解释了为什么值会“反弹”(由于脏检查):。当与浮点的有限精度相结合时,数值可能会振荡0、1或更多次,甚至是无限期振荡,这种效应在IIR DSP滤波器中称为“极限环”。这是一个怎样的评论呢?这个答案非常有助于为$scope设计一个适当的规范化模式;无论是标记和保护(@over热心”答案)还是更好的模式设计都是最好的,可能会因应用程序而异,这两个答案都非常好。
someModule.directive('fahrenheitToCelcius', function() {
  return {
    require: 'ngModel',
    link: function(scope, element, attrs, ngModel) {
      ngModel.$formatters.push(function(f) {
        return (value - 32) * 5.0 / 9.0;
      });
      ngModel.$parsers.push(function(c) {
        return c * 9.0 / 5.0 + 32;
      });
    }
  };
});
fahrenheitBox.bind('change', function() {
  celciusBox.val((Number(fahrenheitBox.val()) - 32) * 5.0 / 9.0);
});