1
votes

I want to watch an object x to see if any of its properties change. The properties are checkboxes. If a user checks the box, it changes the checked property (prop1) to 1.

Each property has certain content within, so if enabled, it should expand the height of the containing element to account for that new content.

        $scope.x = {
            prop1: 0, 
            prop2: 0,
            prop3: 0,
            prop4: 0,
        };

I watch to see if any changes are made in x. If so, the height of the element is updated:

    $scope.$watchCollection('x', function(embed){
        $scope.x.height = $scope.getHeight();
    });

Get height is called, which calls checkOptions() to add to specified buffer space to the element:

    $scope.getHeight = function () {
        $scope.checkOptions();
        return Math.ceil(($scope.totalElements / $scope.totalCols) * elementHeight);
    };

    $scope.checkOptions = function () {
        if ($scope.x.prop1 === 1) {
            elementHeight += 50px;
        }
        ...other properties

The HTML uses a checkbox, checking for true/false:

        <fieldset class="modal-checkbox">
            <input type="checkbox"
                   id="element-prop1"
                   ng-model="x.prop1"
                   ng-true-value="1"
                   ng-false-value="0">
            <label for="element-prop1">
                <span>Element Prop 1</span>
            </label>
        </fieldset>

When I click the checkbox, it keeps adding to the height, and finally:

Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations: [[{"msg":"fn: regularInterceptedExpression","newVal":39,"oldVal":38},{"msg":"fn: expressionInputWatch","newVal":"6168","oldVal":"6006"}],'

I checked Angular $watchCollection, and it seems to do exactly what I want... watch the collection within x object to look for changes...

and $digest says:

Processes all of the watchers of the current scope and its children. Because a watcher's listener can change the model, the $digest() keeps calling the watchers until no more listeners are firing. This means that it is possible to get into an infinite loop.

I don't see why I am getting the loop.

1
Have you tried using $scope.$watch('x', function(embed){}, true); instead? In my experience $watchCollection has never quite worked. The $watch with object equality set to true will do a deep watch of all the prop values. - Davin Tryon
BTW, I don't see anything obvious that would could another digest cycle. But, I can't see the rest of the ... other properties code. If you are mutating anything that is being watched you'll kick off another cycle and enter a loop. - Davin Tryon
@DavinTryon that's what was happening. I am adding a property height to x object, which is mutated, which kicked off another watch. - Growler
Instead of use a $watch, use an ng-change on the checkbox... - Davin Tryon

1 Answers

3
votes

Your watch function is the problem. Whenever you change $scope.x.height, it will detect that x has changed and trigger the watch once more.

Either move that height property out of x and put it somewhere else, or ensure that the value won't be different no matter how many times you run getHeight().

By the way, when you use ng-true-value or ng-false-value, the value will be a string.