2016-12-13 4 views
10

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

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

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

+0

Это лучше, если вам избежать лишних $ часов, как некоторые из ответов здесь показали. Это обходной путь, но по стоимости производительности при масштабировании. Angular _does_ обеспечивает одностороннее связывание данных. Вот ссылка, если вы хотите узнать, как это работает. Https://toddmotto.com/one-way-data-binding-in-angular-1-5/ –

ответ

1

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

Вы можете посмотреть here и official documentation.

$ часы (watchExpression, слушатель, [objectEquality]); Регистрирует обратный вызов слушателя при каждом изменении watchExpression.

Функция watchExpression вызывается при каждом вызове $ digest() и должна вернуть значение, которое будет наблюдаться. (watchExpression не должен изменить его значение при выполнении несколько раз с тем же входом , потому что он может выполняться несколько раз с помощью $ digest(). То есть watchExpression должен быть идемпотентным.) Слушатель вызывается только , когда значение из текущее watchExpression и предыдущий вызов на watchExpression не равны (за исключением начального запуска , см. ниже). Неравенство определяется в соответствии с ссылкой неравенство, строгое сравнение с помощью оператора! == Javascript, если только objectEquality == true (см. Следующую точку) Когда objectEquality == true, неравенство watchExpression определяется в соответствии с угловыми.элементами функция. Чтобы сохранить значение объекта для последующего сравнения , используется функция угловой.copy. Это означает, что , что наблюдение за сложными объектами будет иметь неблагоприятные характеристики памяти и производительность . Это не должно использоваться для наблюдения за изменениями объектов , которые содержат или содержат объекты File из-за ограничений с помощью угловой.copy. Слушатель может изменить модель, которая может вызвать другие слушатели . Это достигается путем повторного просмотра наблюдателей до тех пор, пока не будут обнаружены изменения . Предел повторной итерации равен 10, чтобы предотвратить тупик бесконечного цикла . Если вы хотите получать уведомления, когда вызывается $ digest , вы можете зарегистрировать функцию watchExpression без прослушивателя. (Будьте готовы к несколько вызовов к вашему watchExpression, потому что будет выполнять несколько раз в одном $ переваривать цикла, если обнаруживается изменение .)

После наблюдающий регистрируется с областью, слушатель п является называется асинхронно (через $ evalAsync) для инициализации наблюдателя. В редких случаях это нежелательно, потому что слушатель вызывается, когда результат watchExpression не изменился. Чтобы обнаружить этот сценарий в слушателе fn, вы можете сравнить newVal и oldVal.Если эти два значения идентичны (===), то слушатель был вызван из-за для инициализации.

3

Как сказал Притам. Вы должны использовать $ 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

1

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

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

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

  1. angular.js копия (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}); 
        } 
    
    }; 
    

    });

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