AngularJS:数组之间的数据绑定

时间:2016-12-13 08:42:38

标签: javascript angularjs arrays data-binding

给定一个数组sourceArray我想创建一个targetArray,它取决于第一个的条目。这意味着创建的Array应包含每个源条目的条目,并在sourceArray更改时更新。但是,修改targetArray永远不应该更新源。

只要sourceArray是静态的,Plunker种就可以了。一旦你开始修改源条目,它显然不会正确更新目标,因为我缺乏适当的数据绑定机制。

我是否需要通过观察targetArray手动更新sourceArray或者是否有任何一种由Angular实现的单向数据绑定机制,我可以使用它来保持两个数组同步?

4 个答案:

答案 0 :(得分:3)

正如普里塔姆所说。你应该使用$ watch。但必须将Collection绑定到它,以使其工作。在手表里面合并阵列。

找到这个工作样本:

$scope.$watchCollection(angular.bind(this, function () {
    return this.sourceArray;}), function (newVal, oldVal) {

      var arr = [];
      for(var i in vm.sourceArray){
         var shared = false;
         for (var j in vm.targetArray)
             if (vm.targetArray[j].id == vm.sourceArray[i].id) {
                 shared = true;
                 break; 
             }
         if(!shared) arr.push(vm.sourceArray[i])
      }
      console.log(arr);
      vm.targetArray = vm.targetArray.concat(arr);
    },true);

http://plnkr.co/edit/E2inRLtwfWnb1VBymNNl?p=preview

答案 1 :(得分:1)

您应该使用$watch。然后添加必要的功能。

您可以查看hereofficial documentation.

  

$ watch(watchExpression,listener,[objectEquality]);注册a   只要watchExpression发生变化,就会执行监听器回调。

     

每次调用$ digest()时都会调用watchExpression   返回将要观看的值。 (watchExpression不应该   使用相同的输入多次执行时更改其值   因为它可能会被$ digest()多次执行。那是,   watchExpression应该是幂等的。)只调用监听器   当来的值来自当前的watchExpression和之前的调用   观察表达不相等(除了初始   跑,见下文)。不平等是根据参考确定的   不等式,通过!== Javascript运算符进行严格比较,除非   objectEquality == true(参见下一点)当objectEquality == true时,   watchExpression的不等式是根据的确定的   angular.equals函数。保存对象的值以供日后使用   比较,使用angular.copy函数。因此这意味着   观看复杂的物体会产生不良的记忆和表现   影响。这不应该用于监视对象的变化   由于angular.copy的限制,它是或包含File对象。   手表监听器可能会更改模型,这可能会触发其他模型   听众要开火。这是通过重新运行观察者直到没有   检测到更改。重新运行迭代限制为10以防止   无限循环死锁。如果您想在$ digest时收到通知   调用,你可以注册一个没有监听器的watchExpression函数。   (准备多次调用watchExpression,因为它   如果发生变化,将在单个$摘要周期中多次执行   检测。)

     

在观察者注册范围后,监听器fn是   异步调用(通过$ evalAsync)来初始化观察者。在   在极少数情况下,这是不可取的,因为在何时调用侦听器   watchExpression的结果没有改变。检测这种情况   在监听器fn中,您可以比较newVal和oldVal。如果   这两个值是相同的(===)然后监听器被调用   初始化。

答案 2 :(得分:1)

您可以使用$ watch表达式。

这是另一种方式:-(下载underscore.js或CDN)

http://plnkr.co/edit/hrOrEdaQ0M7wEgWlRHlO?p=preview

  1. angular.js copy(angular.copy())方法。
  2. underscore.js扩展方法。

     var app = angular.module('plunker', []);
        app.controller('MainCtrl', function($scope) {
            var vm = this;
            vm.sourceArray = [{id: '0', name: 'someObject'}, {id: '1', name: 'anotherObject'}];
            vm.targetArray = angular.copy(vm.sourceArray);
           // angular.copy(vm.sourceArray, vm.targetArray);
            vm.push = function(){
              let found = false;
              angular.forEach(vm.sourceArray, function(el){
                if (el.id === vm.id){
                  el.name = vm.name;
                  found = true;
                }
              });
              if (!found){
                vm.sourceArray.push({id: vm.id, name: vm.name});
               _.extend(vm.targetArray, vm.sourceArray);
              }
    
        };
    
    
    
    vm.pushTarget = function(){
      let found = false;
      angular.forEach(vm.targetArray, function(el){
        if (el.id === vm.id1){
          el.name = vm.name1;
          found = true;
        }
      });
      if (!found){
        console.log({id: vm.id, name: vm.name})
        vm.targetArray.push({id: vm.id1, name: vm.name1});  
      }
    
    };
    

    });

  3. 你可以获得underscore.js代码: -

    _.extend = createAssigner(_.allKeys);
    
    // An internal function for creating assigner functions.
    var createAssigner = function(keysFunc, undefinedOnly) {
        return function(obj) {
          var length = arguments.length;
          if (length < 2 || obj == null) return obj;
          for (var index = 1; index < length; index++) {
            var source = arguments[index],
                keys = keysFunc(source),
                l = keys.length;
            for (var i = 0; i < l; i++) {
              var key = keys[i];
              if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
            }
          }
          return obj;
        };
      };
    
      // Retrieve all the property names of an object.
      _.allKeys = function(obj) {
        if (!_.isObject(obj)) return [];
        var keys = [];
        for (var key in obj) keys.push(key);
        // Ahem, IE < 9.
        if (hasEnumBug) collectNonEnumProps(obj, keys);
        return keys;
      };
    
       // Extend a given object with all the properties in passed-in object(s).
    

答案 3 :(得分:1)

这是我制作的片段。请注意,更改源阵列时,两个阵列都会受到影响,但是当您仅更改目标时,源保持不变。

angular.module('app', [])
  .controller('mainCtrl', function($scope) {
    var vm = this;
    vm.sourceArray = [];
    vm.source = '["change me!",{"a":3},[100]]';

    $scope.$watch('vm.source', function(newVal) {
      try {
        vm.sourceArray = JSON.parse(newVal);
        vm.target = newVal;
        vm.serr = null;
      } catch (e) {
        vm.serr = 'Invalid JSON';
      }
    });
  
  $scope.$watch('vm.target', function(newVal) {
      try {
        vm.targetArray = JSON.parse(newVal);
        vm.terr = null;
      } catch (e) {
        vm.terr = 'Invalid JSON';
      }
    });

    //Copy whole array on change
    $scope.$watch('vm.sourceArray', function(newVal) {
      vm.targetArray = angular.copy(newVal);
    }, true);

    return this;
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="mainCtrl as vm">
  <span>Change the inputs one at a time to see the changes take effect</span>
  <h5>Source:</h5>
  <input type="text" ng-model="vm.source" ng-model-options="{debounce: 300}" placeholder="Enter json formatted string for source array"><span>{{vm.serr}}</span>
  <div>Model: {{vm.sourceArray|json:null:2}}</div>
  <br>
  <h5>Target:</h5>
  <input type="text" ng-model="vm.target" ng-model-options="{debounce: 300}" placeholder="Enter json formatted string for source array"><span>{{vm.terr}}</span>
  <div>Model: {{vm.targetArray|json:null:2}}</div>
</div>