AngularJS: привязка данных между массивами

Учитывая массив sourceArray, я хотел бы создать targetArray, который зависит от записей первого. Это означает, что созданный массив должен содержать запись для каждой из исходных записей и обновляться при каждом изменении sourceArray. Однако изменение targetArray никогда не должно обновлять источник.

Этот Plunker работает, пока sourceArray статичен. Как только вы начнете изменять исходные записи, он, очевидно, не обновит цель должным образом, потому что мне не хватает надлежащего механизма привязки данных.

Нужно ли обновлять targetArray вручную, наблюдая за sourceArray или существует какой-то механизм 1-way-databinding, реализованный с помощью Angular, который я могу использовать для синхронизации двух массивов?

Ответ 1

Как сказал Притам. Вы должны использовать $watch. Но он должен привязать коллекцию к ней, чтобы она работала. И внутри часы сливают массивы.

Найдите этот рабочий образец:

$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

Ответ 2

Вы должны использовать $watch. Затем добавьте нужную функцию.

Вы можете посмотреть здесь и официальную документацию

Ответ 3

Вы можете использовать выражение $watch.

Вот еще один способ:-( скачать underscore.js или CDN)

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

  • angular.js copy (angular.copy()).
  • метод расширения 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});  
      }
    
    };
    

    });

вы можете получить код 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).

Ответ 4

Вот фрагмент, который я сделал. Обратите внимание, что при изменении исходного массива затронуты оба массива, однако при изменении только цели источник остается неповрежденным.

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>