Angular js - Выделите dom при изменении значения

Angular noobie здесь. Я хотел бы знать, что является лучшим способом изменить dom, когда значение в области изменяется каким-то образом. Я читал, что нехорошо поставить логику манипуляции dom в контроллер, и это задача директив.

Вот plunkr

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

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

Любая помощь?

Ответ 1

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

<td highlighter="person.firstName">{{ person.firstName }}</td>

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

app.directive('highlighter', ['$timeout', function($timeout) {
  return {
    restrict: 'A',
    scope: {
      model: '=highlighter'
    },
    link: function(scope, element) {
      scope.$watch('model', function (nv, ov) {
        if (nv !== ov) {
          // apply class
          element.addClass('highlight');

          // auto remove after some delay
          $timeout(function () {
            element.removeClass('highlight');
          }, 1000);
        }
      });
    }
  };
}]);

Хотя для этого вам нужно будет сообщить angular, что данные действительно изменились. В настоящее время это не так, как angular отслеживает people по идентификатору объекта. В тот момент, когда вы перезапишите его, angular удалит все связанные элементы dom. Для этого используйте:

ng-repeat="person in people track by $index"

который сообщит angular обработать индекс массива как идентификатор.

demo: http://jsbin.com/vutevifadi/1/

Ответ 2

Спасибо за отправку ответа выше. Я заметил, что анимация будет мерцать, если значение изменяется часто, и тайм-аут будет запущен, пока еще активна другая анимация.

Я исправил это, сбросив таймаут, если тайм-аут уже установлен.

Кроме того, я добавил код, чтобы проверить, увеличивается или уменьшается значение, и задает другой класс css.

app.directive('newvalue', ['$timeout', function($timeout) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
        element.addClass('newvalue');
        scope.$watch(attrs.newvalue, function (nv, ov) {
        function settimeout() {
            attrs.timeout = $timeout(function () {
                element.removeClass('newvalue-up');
                element.removeClass('newvalue-down');
                attrs.timeout = null;
            }, 1000);
        }
        if (nv !== ov) {
            if(attrs.timeout) {
                //newvalue already set.. reset timeout
                $timeout.cancel(attrs.timeout);
                settimeout();
            } else {
                if(nv > ov) {
                    element.addClass('newvalue-up');
                } else {
                    element.addClass('newvalue-down');
                }
                settimeout();
            }
        }
      });
    }
  };
}]);

Ответ 3

После некоторого чтения я заметил, что есть некоторые сомнения в использовании $watch, учитывая производительность. Я нашел другое решение, используя $observe.

Хорошо читать на $watch и $observe: fooobar.com/info/18387/...

JavaScript:

 
var app = angular.module('angularjs-starter', []);
app.directive('highlightOnChange', function() {
  return {
    link : function(scope, element, attrs) {
      attrs.$observe( 'highlightOnChange', function ( val ) {
        console.log("Highlighting", val);
        element.effect('highlight');
      });
    }
  };
});

app.controller('myController', function($scope, $timeout) {
  $scope.val = 1;
  $scope.updateVal = function() {
    $scope.val = $scope.val + 1;
  };
}); 

HTML:                                               

  <body ng-controller="myController">
    <div highlight-on-change="{{val}}">
      Total: {{ val }}
    </div>
    <button ng-click="updateVal()">Add to Total</button>
  </body>

исходный источник: http://plnkr.co/edit/FFBhPIRuT0NA2DZhtoAD?p=preview из этого сообщения: https://groups.google.com/d/msg/angular/xZptsb-NYc4/YH35m39Eo2wJ

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

<table class="table table-hover">
        <tr>
            <th ng-repeat="col in fc.tableColumns"><!--fc is a controller-->
                {{col.displayName}}
            </th>
        </tr>
        <tr ng-repeat="item in fc.items track by item.id">
            <td highlight-on-change="{{value}}" ng-repeat="(key,value) in item">
               @*{{key}} =*@ {{value}}
            </td>
        </tr>
    </table>

Как я уже сказал, обновляет конкретный столбец, делая это где-то в контроллере.

 
items[index] = item;//item from server