AngularJs $与2路结合观看 [英] AngularJs $watch with 2 way binding

查看:138
本文介绍了AngularJs $与2路结合观看的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创造一个有范围滑块的影响海誓山盟取决于他们是怎么设置的页面。我有一个手表的功能,看起来像下面的作品的一种方式,但是我想有手表的效果是双向的,但我不能找出是否有一种方法,我可以做到这一点无需为每个值制作一个(大约有12滑块)。

I'm creating a page where there are range sliders that effect eachother depending on what they're set at. I have a watch function that looks like below, that works one way, however I'd like to have the watch effect both ways, but I can't figure out if there is a way I can do this without creating one for each value (there are about 12 sliders).

下面是Plunker勾画我试图做的事:
http://plnkr.co/edit/CXMeOT?p=$p$pview

Here is a Plunker outlining what I am trying to do: http://plnkr.co/edit/CXMeOT?p=preview

推荐答案

我想通了三种不同的方法来做到这一点的双向计算的值绑定。我只写了资产的解决方案滑块,而不是 ROA 滑块,因为我资产是一个基本的总和, ROA 是别的东西都在一起。 (@flashpunk:请解释一下,如果你需要与你的问题这方面更多的帮助。)为什么这是困难的,关键的问题是,在JavaScript中,数字是不会重新在precise基地10 psented $ P $格式;遇到IM precision的这方面的损失时,角进入一个无限循环的基础上,所造成的IM precision的变化重新计算的变化。

I figured out three different ways to do this bidirectional binding of computed values. I only wrote the solution for the assets sliders and not the roa sliders, since I assets is a basic sum, and roa is something else all together. (@flashpunk: Please explain, if you need more help with that aspect of your question.) The key issue for why this is difficult is that, in javascript, numbers are not represented in a precise base 10 format; when this loss of imprecision is encountered, angular goes into an infinite loop, recalculating the changes based on the changes caused by the imprecision.

在换言之,问题在于,数值计算是<青霉>有损的,不会如果计算是发生这些问题的无损

In other words, the problem is that numerical calculations are lossy, these problems would not occur if the calculations were lossless.

这是我的第一个解决方案。它采用了(脆弱)锁定机制切换,这取决于值更改规范数据源。为了使该解决方案更健壮,我想创建一个扩展范围,以便更加先进和复杂的观察家的角度模块。如果我碰上将来出现问题,我可能会开始在GitHub上的一个项目;如果我这样做,我会修改这个答案。

This was my first solution. It uses a (fragile) locking mechanism to switch the canonical data source depending on which value was changed. In order to make this solution more robust, I would create an angular module that extends Scope to allow for more advanced and complex watchers. If I run into the problem in the future, I may start a project on github; I'll revise this answer if I do so.

// Both of these functions can be replaced with library functions from lodash or underscore, etc.
var sum = function(array) { return array.reduce(function(total, next) { return total + (+next); }, 0) };
var closeTo = function(a, b, threshold) { return a == b || Math.abs(a - b) <= threshold; };

$scope.sliders = [
$scope.slide1 = {
  assets: 10,
  roa: 20
}, ... ];

$scope.mainSlide = {
  assets: 0,
  roa: 0
};
// you might want to make or look for a helper function to control this "locking"
// in a better fashion, that integrates and resets itself with the digest cycle
var modifiedMainAssets = false;
var modifiedCollectionAssets = false;
$scope.$watch(function() {
      return sum($scope.sliders.map(function(slider) { return slider.assets; }))
    }, function(totalAssets) {
  if (modifiedCollectionAssets) { modifiedCollectionAssets = false; return; }
  $scope.mainSlide.assets = totalAssets;
  modifiedMainAssets = true;
});
$scope.$watch('mainSlide.assets', function(totalAssets, oldTotalAssets) {
  if (modifiedMainAssets) { modifiedMainAssets = false; return; }
  if (oldTotalAssets === null || closeTo(totalAssets, oldTotalAssets, 0.1)) { return; }

  // NOTE: has issues with floating point math. either round & accept the failures,
  // or use a library that supports a proper IEEE 854 decimal type
  var incrementAmount = (totalAssets - oldTotalAssets) / $scope.sliders.length;
  angular.forEach($scope.sliders, function(slider) { slider.assets += incrementAmount; });
  modifiedCollectionAssets = true;
});

方法2

在这个版本中,我避免了笨重锁定机制,统一与什么是目前的角度提供的观察家。我用的滚条值作为标准数据源,并重新计算的基础上有多大改变总。此外,内置的设施不足以彻底EX pressing的问题,我需要手动保存 oldValues​​ 。 (在code可能是更清洁,但我没想到有进行上述操作)。

Approach 2

In this version, I avoid the clunky locking mechanism, and unify the watchers with what's currently available in angular. I use the individual sliders' values as the canonical data source, and recalculate the total based on how much has changed. Again, the built-in facilities are inadequate for thoroughly expressing the issue, and I need to manually save the oldValues. (The code could be cleaner, but as I didn't anticipate having to perform the aforementioned operation).

$scope.calculateSum = function() {
  return sum($scope.sliders.map(function(slider) { return slider.assets; }));
};
$scope.mainSlide.assets = $scope.calculateSum();
var modifiedMainAssets = false;
var modifiedCollectionAssets = false;
var oldValues = [$scope.mainSlide.assets, $scope.mainSlide.assets];
$scope.$watchCollection('[calculateSum(), mainSlide.assets]'
    , function(newValues) {
  var newSum = newValues[0];
  var oldSum = oldValues[0];
  var newAssets = newValues[1];
  var oldAssets = oldValues[1];
  if (newSum !== oldSum) {
    $scope.mainSlide.assets = newSum;
  }
  else if (newAssets !== oldAssets) {
    var incrementAmount = (newAssets - oldAssets) / $scope.sliders.length;
    angular.forEach($scope.sliders, function(slider) { slider.assets += incrementAmount; });
    $scope.mainSlide.assets = $scope.calculateSum();
  }
  oldValues = [$scope.mainSlide.assets, $scope.mainSlide.assets];
});

方法3:回到基础

这是我大概应该摆在首位劝告。有一个规范的数据源,这是单个的滑动器。对于主滑块,创建自定义的滑动指令,与其有一个NG-模式,即触发报告所做的更改的事件。 (你可以用叉子或现有指令做到这一点。)

Approach 3: Back to basics

This is what I probably should have advised in the first place. Have one canonical data source, which are the individual sliders. For the main slider, create a custom slider directive that, instead of having an ng-model, fires events that report the changes made. (You can wrap or fork an existing directive to do this.)

$scope.$watch('calculateSum()', function(newSum, oldSum) {
    $scope.mainSlide.assets = newSum;
});
$scope.modifyAll = function(amount) {    
    angular.forEach($scope.sliders, function(slider) { slider.assets += amount; });
};

修订的html:

Revised html:

Assets: <span ng-bind="mainSlide.assets"></span>
<button ng-click="modifyAll(1)">Up</button>
<button ng-click="modifyAll(-1)">Down</button>

审核

此似乎是角队尚未解决的一个问题。基于事件的数据绑定系统(什么在淘汰赛,余烬和骨干网使用)将由根本没有射击是有损耗的具体计算的变化改变事件解决这个问题;在棱角分明的情况下,一些调整需要做的消化周期。我不知道如果我的头两个解决方案是什么会被MISKO或其他角度大师被告知,但他们的工作。

Review

This seems to be a problem that the angular team has yet to address. Event-based data binding systems (what's used in knockout, ember and backbone) would address this by simply not firing the change event on the specific computed change that is lossy; in angular's case, some tweaking needs to be done to the digest cycle. I have no idea if my first two solutions are what would be advised by Misko or another angular guru, but they work.

现在,我想preFER方法3.如果不能满足你,使用方法2和清理;但使用无损十进制或部分重新presentation,而不是内置的JavaScript号码类型(这样为小数这一点,分数)。 - https://www.google.com/search?q=javascript+number + libaries

For now, I would prefer Approach 3. If that doesn't satisfy you, use approach 2, and clean it up; but use a lossless decimal or fraction representation, not the built-in javascript Number type (like this for decimal or this, for fractional). -- https://www.google.com/search?q=javascript+number+libaries

这篇关于AngularJs $与2路结合观看的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆