Peter Ehrlich Peter Ehrlich - 10 months ago 36
AngularJS Question

Angular `$watchCollection` returning undefined oldVal in test

I am running a Jasmine spec on a directive compiled from markup.

With the following method in a directive:

scope.$watchCollection 'x', ->
console.log arguments

And the following test:

it "adds to array", ->
scope.$apply( ->
scope.x = []
scope.$apply( ->

I get the following console output:

[undefined, undefined, Scope]
jasmine-specs.js:63717 [Array[0], undefined, Scope]
jasmine-specs.js:63717 [Array[1], undefined, Scope]

This seems broken. I would expect the second argument of the last line to be "Array[0]", the previous value of the collection. Why would this not be?


I was able to reproduce the same thing here, and I was confused too until I saw this in the angular docs for $watchCollection:

The oldCollection object is a copy of the former collection data. Due to performance considerations, theoldCollection value is computed only if the listener function declares two or more arguments.

This is referring to this:

$scope.$watchCollection('x', function() {

vs this:

$scope.$watchCollection('x', function(oldVal, newVal) {

(I know this is not using the lambda syntax, but it's the same solution)

So the oldCollection will always be undefined unless you actually declare the 1st and 2nd arguments to hold the new and old value. Then it will show up as Array[0] as you expected. This plunkr will show that.

Edit: I think the other syntax would be:

scope.$watchCollection 'x', (old, new) ->
    console.log arguments