Как глубоко смотреть массив в angularjs?


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

Это мой код:

function TodoCtrl($scope) {
  $scope.columns = [
      { field:'title', displayName: 'TITLE'},
      { field: 'content', displayName: 'CONTENT' }
  ];
   $scope.$watch('columns', function(newVal) {
       alert('columns changed');
   });
}

но когда я изменяю значения, например, я изменяю TITLE to TITLE2 на alert('columns changed') никогда не совал.

как глубоко наблюдать объекты внутри массива?

есть демо-версия:http://jsfiddle.net/SYx9b/

10 307

10 ответов:

вы можете установить 3-й аргумент $watch до true:

$scope.$watch('data', function (newVal, oldVal) { /*...*/ }, true);

посмотреть https://docs.angularjs.org/api/ng/type/метрики.Объем#$смотреть

С Углового 1.1.x вы также можете использовать $watchCollection для просмотра мелких часов (только "первый уровень") коллекции.

$scope.$watchCollection('data', function (newVal, oldVal) { /*...*/ });

см.https://docs.angularjs.org/api/ng/type/$rootScope. Scope#$watchCollection

есть последствия производительности для глубокого погружения объекта в вашем $watch. Иногда (например, когда изменения только выталкиваются и всплывают), вы можете захотеть $watch легко вычисляемое значение, такое как array.длина.

если вы собираетесь посмотреть только один массив, вы можете просто использовать этот кусок кода:

$scope.$watch('columns', function() {
  // some value in the array has changed 
}, true); // watching properties

пример

но это не будет работать с несколькими массивами:

$scope.$watch('columns + ANOTHER_ARRAY', function() {
  // will never be called when things change in columns or ANOTHER_ARRAY
}, true);

пример

чтобы справиться с этой ситуацией, я обычно преобразую несколько массивов, которые я хочу посмотреть в JSON:

$scope.$watch(function() { 
  return angular.toJson([$scope.columns, $scope.ANOTHER_ARRAY, ... ]); 
},
function() {
  // some value in some array has changed
}

пример

как @jssebastian указал в комментариях,JSON.stringify может быть предпочтительнее angular.toJson поскольку он может обрабатывать элементы, которые начинаются с " $ " и возможных других случаев.

стоит отметить, что в угловых 1.1.X и выше, теперь вы можете использовать $watchCollection а не $ watch. Хотя $watchCollection, похоже, создает мелкие часы, поэтому он не будет работать с массивами объектов, как вы ожидаете. Он может обнаруживать добавления и удаления в массив, но не свойства объектов внутри массивов.

$watchCollection свершать то, что вы хотите сделать. Ниже приведен пример скопирован с сайта в AngularJS http://docs.angularjs.org/api/ng/type/метрики.Область Хотя это удобно, производительность должна быть принята во внимание, особенно когда вы смотрите большую коллекцию.

  $scope.names = ['igor', 'matias', 'misko', 'james'];
  $scope.dataCount = 4;

  $scope.$watchCollection('names', function(newNames, oldNames) {
     $scope.dataCount = newNames.length;
  });

  expect($scope.dataCount).toEqual(4);
  $scope.$digest();

  //still at 4 ... no changes
  expect($scope.dataCount).toEqual(4);

  $scope.names.pop();
  $scope.$digest();

  //now there's been a change
  expect($scope.dataCount).toEqual(3);

вот сравнение 3 способов, которыми вы можете смотреть переменную scope с примерами:

$watch () запускается:

$scope.myArray = [];
$scope.myArray = null;
$scope.myArray = someOtherArray;

$watchCollection() запускается все выше и:

$scope.myArray.push({}); // add element
$scope.myArray.splice(0, 1); // remove element
$scope.myArray[0] = {}; // assign index to different value

$ watch(..., правда) запускается все выше и:

$scope.myArray[0].someProperty = "someValue";

ЕЩЕ ОДНА ВЕЩЬ...

$watch () это единственный, который срабатывает, когда массив заменяется другим массивом, даже если этот другой массив имеет то же самое точное содержимое.

здесь $watch() будут стрелять и $watchCollection() не будет:
$scope.myArray = ["Apples", "Bananas", "Orange" ];

var newArray = [];
newArray.push("Apples");
newArray.push("Bananas");
newArray.push("Orange");

$scope.myArray = newArray;

Ниже приведена ссылка на пример JSFiddle, который использует все различные комбинации часов и выводит сообщения журнала, чтобы указать, какие "часы" были вызваны:

http://jsfiddle.net/luisperezphd/2zj9k872/

Это решение работает очень хорошо для меня, я делаю это в директиву:

объем.$watch(attrs.testWatch, function () {.....}, true);

true работает довольно хорошо и реагирует на все chnages (добавление, удаление или изменение поля).

вот рабочий плунжер для игры с ним.

глубоко наблюдая за массивом в AngularJS

Я надеюсь, что это может быть полезным для вас. Если у вас есть какие-либо вопросы, не стесняйтесь спрашивать, я буду попробую помочь :)

в моем случае мне нужно было наблюдать за сервисом, который содержит объект адреса, также наблюдаемый несколькими другими контроллерами. Я застрял в цикле, пока не добавил параметр "true", который, похоже, является ключом к успеху при просмотре объектов.

$scope.$watch(function() {
    return LocationService.getAddress();
}, function(address) {
    //handle address object
}, true);

задание objectEquality параметр (третий параметр)$watch функция, безусловно, правильный способ смотреть все свойства массива.

$scope.$watch('columns', function(newVal) {
    alert('columns changed');
},true); // <- Right here

Пиран отвечает на это достаточно хорошо и упоминает $watchCollection как хорошо.

Более Подробно

причина, по которой я отвечаю на уже ответленный вопрос, заключается в том, что я хочу указать, что wizardwerdnaответ не является хорошим и не должен быть используемый.

проблема в том, что переваривание происходит не сразу. Они должны дождаться завершения текущего блока кода перед выполнением. Таким образом, смотрите length массива может на самом деле пропустить некоторые важные изменения, которые $watchCollection будет ловить.

предположим, что эта конфигурация:

$scope.testArray = [
    {val:1},
    {val:2}
];

$scope.$watch('testArray.length', function(newLength, oldLength) {
    console.log('length changed: ', oldLength, ' -> ', newLength);
});

$scope.$watchCollection('testArray', function(newArray) {
    console.log('testArray changed');
});

на первый взгляд может показаться, что они будут стрелять одновременно, например, в этом случае:

function pushToArray() {
    $scope.testArray.push({val:3});
}
pushToArray();

// Console output
// length changed: 2 -> 3
// testArray changed

это работает достаточно хорошо, но рассмотрим это:

function spliceArray() {
    // Starting at index 1, remove 1 item, then push {val: 3}.
    $testArray.splice(1, 1, {val: 3});
}
spliceArray();

// Console output
// testArray changed

обратите внимание, что результирующая длина была такой же, даже если массив имеет новый элемент и потерял элемент, так как часы, как $watch обеспокоен, length ничего не изменилось. $watchCollection взял на него, хотя.

function pushPopArray() {
    $testArray.push({val: 3});
    $testArray.pop();
}
pushPopArray();

// Console output
// testArray change

тот же результат происходит с толчком и поп в том же блоке.

вывод

чтобы просмотреть каждое свойство в массиве, используйте $watch на массиве iteself с помощью третий параметр (objectEquality) включен и установлен в true. Да, это дорого, но иногда надо.

чтобы наблюдать, когда объект входит / выходит из массива, используйте $watchCollection.

не используйте $watch на length свойства массива. У меня почти нет веской причины так поступать.

$scope.changePass = function(data){
    
    if(data.txtNewConfirmPassword !== data.txtNewPassword){
        $scope.confirmStatus = true;
    }else{
        $scope.confirmStatus = false;
    }
};
  <form class="list" name="myForm">
      <label class="item item-input">        
        <input type="password" placeholder="ใส่รหัสผ่านปัจจุบัน" ng-model="data.txtCurrentPassword" maxlength="5" required>
      </label>
      <label class="item item-input">
        <input type="password" placeholder="ใส่รหัสผ่านใหม่" ng-model="data.txtNewPassword" maxlength="5" ng-minlength="5" name="checknawPassword" ng-change="changePass(data)" required>
      </label>
      <label class="item item-input">
        <input type="password" placeholder="ใส่รหัสผ่านใหม่ให้ตรงกัน" ng-model="data.txtNewConfirmPassword" maxlength="5" ng-minlength="5" name="checkConfirmPassword" ng-change="changePass(data)" required>
      </label>      
       <div class="spacer" style="width: 300px; height: 5px;"></div> 
      <span style="color:red" ng-show="myForm.checknawPassword.$error.minlength || myForm.checkConfirmPassword.$error.minlength">รหัสผ่านต้องมีจำนวน 5 หลัก</span><br>
      <span ng-show="confirmStatus" style="color:red">รหัสผ่านใหม่ไม่ตรงกัน</span>
      <br>
      <button class="button button-positive  button-block" ng-click="saveChangePass(data)" ng-disabled="myForm.$invalid || confirmStatus">เปลี่ยน</button>
    </form>