1

Is there a way to visually show when a scoped input value is changed programmatically?

I have several input fields that are bound to various ng-model values, and these values change outside the user's control. (The change is tied to a button in the example below for simplicity.)

When the values change, I want the input to change color or show some kind of visual cue to make it obvious that the value isn't the same as a second ago. If there was only one field, this could probably be done with a watch and adding some CSS to the relevant input. However, in production there are hundreds of values, we don't have a mapping of which values are shown in which inputs, and even if we did, many inputs are generated by repeaters, so hand coding countless watches is out.

I was hoping for something like the jQuery highlight effect (http://api.jqueryui.com/highlight-effect/) but at this point, I'd be interested in any visual change at all to see if I can make it work for what I need.

Sample fiddle here: http://jsfiddle.net/cdnaa8ew/1/

angular.module('changeSample', [])
  .controller('SampleController', ['$scope',
    function($scope) {
      $scope.a = 1;
      $scope.b = 2;
      $scope.c = 3;
      $scope.d = 4;
      $scope.e = 5;

      $scope.change = function() {
        var rand = Math.floor(Math.random() * 5);
        if (rand == 0) {
          $scope.a = $scope.a + 1;
        }
        if (rand == 1) {
          $scope.b = $scope.b + 1;
        }
        if (rand == 2) {
          $scope.c = $scope.c + 1;
        }
        if (rand == 3) {
          $scope.d = $scope.d + 1;
        }
        if (rand == 4) {
          $scope.e = $scope.e + 1;
        }
      };
    }
  ]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>

<body ng-app="changeSample">
  <form ng-controller="SampleController">
    <input type="text" ng-model="a" />
    <br/>
    <input type="text" ng-model="b" />
    <br/>
    <input type="text" ng-model="c" />
    <br/>
    <input type="text" ng-model="d" />
    <br/>
    <input type="text" ng-model="e" />
    <br/><span>{{a}}{{b}}{{c}}{{d}}{{e}}</span>

    <br/>
    <button ng-click="change()">Change</button>
  </form>
</body>
Nathan Rabe
  • 665
  • 1
  • 6
  • 10

2 Answers2

2

You can create a simple directive for that which would add a class to changed element. For example:

.directive('highlight', function($timeout) {
    return {
        require: 'ngModel',
        link: function(scope, element, attrs) {
            var className = attrs.highlight || 'highlight';
            scope.$watch(attrs.ngModel, function(newVal, oldVal) {
                if (newVal !== oldVal) {
                    element.addClass(className);
                    $timeout(function() {
                        element.removeClass(className);
                    }, 400);
                }
            });
        }
    };
});

And use it like this:

<input type="text" ng-model="c" highlight />
<input type="text" ng-model="d" highlight="highlight-red" />

Then you can define whatever highlight style want using CSS:

.highlight-red {
    -webkit-transition: background .4s ease;
    transition: background .4s ease;
    background: #FE94B3;
}

Demo: http://jsfiddle.net/cdnaa8ew/3/

dfsq
  • 191,768
  • 25
  • 236
  • 258
  • I had to make a small modification to avoid the highlight if the user was typing the new value, but otherwise this worked well in small tests. Still have to see if there will be too many watches in production as there are far more than 5 fields on the screen at a time. – Nathan Rabe Oct 15 '14 at 13:57
  • Performance should be fine unless there are 2000 fields on the page (which you shouldn't have anyway). – dfsq Oct 15 '14 at 14:39
  • @NathanRabe: which small modifications did you make? – Hendrik Jan Oct 26 '17 at 14:28
  • 1
    @HendrikJan Well, it was 3 years ago, so I don't really remember. I suspect it was either a check if the input field had focus or if the new value was already present in the field. – Nathan Rabe Oct 26 '17 at 16:21
  • @NathanRabe thanks. I changed ```newVal !== oldVal``` to ```newVal !== oldVal && element.get(0) !== document.activeElement``` and it works. – Hendrik Jan Oct 27 '17 at 08:06
0

Angular animate can be bound to a number of events such as ng-show and ng-repeat. https://docs.angularjs.org/api/ngAnimate/service/$animate

This would allow you to replicate the jquery highlight effect. Also, check out this related question: ng-animate : Animation when model changes

Community
  • 1
  • 1
Duncan
  • 2,550
  • 2
  • 17
  • 18
  • This looks like more than a link only answer to me - it tells us about various properties that may be helpful for future readers to know about even if the link breaks. – ArtOfWarfare Oct 14 '14 at 17:07