6

I use this function to watch an array of objects for changes:

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

How can I get an object in which property has been changed so that I can push it in an array? For example:

var myApp = angular.module("myApp", []);

myApp.factory("Data", function(){
var Data = [{id:1, property: "Random"}, {id:2, property: "Random again"}];
return Data;
});

var myBigArray = [];

function tableCtrl($scope, Data){
    $scope.TheData = Data;
    $scope.$watch("TheData", function() {

    //Here an object should be pushed
    myBigArray.push(">>Object in which property has been changed <<<");
    }, true);
}
CoolCodeBro
  • 769
  • 3
  • 9
  • 14
  • 1
    Would help to see how items are changed. Might have access to the object at that point. Code shown is far too simplified. Create a demo that shows use case. Also why do you need array stored as global outside of angular? – charlietfl Apr 20 '13 at 18:21

3 Answers3

2

I don't see a way currently in Angular to get the changed object... I suspect you might need to traverse the new array and try to find the differences with the old array...

Shai Reznik - HiRez.io
  • 8,748
  • 2
  • 33
  • 33
  • It's 2015 now. Is there any update on this topic? I spent this whole day searching how to detect the object that is being changed with no luck. Hate to use deep watch and manual compare. – Codism Sep 25 '15 at 03:29
2

Edit: Note that this solution turns out to be a bad practice as it is adding a lot of watchers, which is something you do not want because it has a performance penalty.

=======

I eventually came up with this solution:

items.query(function (result) {
    _(result).each(function (item, i) {
        $scope.items.push(item);
        $scope.$watch('items[' + i + ']' , function(){
            console.log(item); // This is the item that changed.
        }, true);
    });
});
Bas Slagter
  • 9,831
  • 7
  • 47
  • 78
  • I know this answer is over 2 years old, but it came up on a google search so I'm going to add a warning to it. You need to be REALLY careful with how many watches you add. Adding a watch for every item in the list could really slow down your app if the list gets too large. – D_Naish Jun 11 '15 at 20:39
  • 1
    @D_Naish I totally agree. Back then when I posted the answer I (along with many people I think) wasn't that aware of the problems you can have with watches. Funny to see how fast things change. Thanks for the comment! – Bas Slagter Jun 12 '15 at 07:08
0

There is still no option like this for $watch, but you can use jQuery plugin for that, http://archive.plugins.jquery.com/project/jquery-diff

I implemented undo/redo with AngularJS using $watch, mb this can help

//History Manager Factory
.factory('HistoryManager', function () {
    return function(scope) {

        this.container = Array();
        this.index = -1;
        this.lock = false;

        //Insert new step into array of steps
        this.pushDo = function() {
            //we make sure that we have real changes by converting to json, 
            //and getting rid of all hash changes
            if(this.container.length == 0 || (angular.toJson(scope.widgetSlider) != angular.toJson(this.container[this.index][0]))) {
                //check if current change didn't came from "undo" change'
                if(this.lock) {
                    return;
                }
                //Cutting array, from current index, because of new change added
                if(this.index < this.container.length-1) {
                    this.container = this.container.slice(0, this.index+1);
                }

                var currentStepSlider = angular.copy(scope.widgetSlider);
                var selectedWidgetIndex = scope.widgetSlider.widgets.indexOf(scope.widgetCurrent);
                //Initialising index, because of new "Do" added
                this.index = this.container.length;
                this.container.push([currentStepSlider, selectedWidgetIndex]);

                if (this.onDo) {
                    this.onDo();
                }
            }
        }


        //Upon undo returns previous do
        this.undo = function() {
            this.lock = true;
            if(this.index>0){
                this.index--;
                scope.widgetSlider = angular.copy(this.container[this.index][0]);
                var selectedWidgetIndex = this.container[this.index][1];
                scope.widgetCurrent = scope.widgetSlider.widgets[selectedWidgetIndex];
            }
            this.lock = false;
        }

        //Upon redo returns next do
        this.redo = function() {
            if(this.index < this.container.length-1) {
                this.index++;
                scope.widgetSlider = angular.copy(this.container[this.index][0]);
                var selectedWidgetIndex = this.container[this.index][1];
                scope.widgetCurrent = scope.widgetSlider.widgets[selectedWidgetIndex];
            }
        }
    }
})

;

Vova Lando
  • 558
  • 3
  • 15