AngularJS 1.4.8 - ngOptions in a select - infinite $digest() loop when I programmatically set model before option is in ngOptions
Asked Answered
F

1

7

I encountered this when migrating from 1.2.14 to 1.4.8. This works fine in 1.2.14, but I get an infinite $digest() loop in 1.4.8. Here is a Fiddle demonstrating the problem. The Fiddle is a lot easier to look at than this post, but SO is making me include code

I have a select element that looks like this:

<select ng-model="selectedId" ng-options="opt.id as opt.label for opt in getOptions()">

My options are objects, like this:

$scope.options = [ { id: 1, label: 'one' }, { id: 2, label: 'two' } ];

The array of options I want to give the ngOptions directive depends on conditions; sometimes I just want to give it $scope.options, but sometimes I want to include another option.

$scope.getOptions = function() {
    if ($scope.showThirdOption)
        return [{ id: 3, label: 'three' }].concat($scope.options);
    else
        return $scope.options;
};

Now, if I programmatically set my model to 3:

...
$scope.selectedId = 3;
...

...Angular won't be upset, even though that option doesn't exist. It just adds an <option> node to the <select> element: <option value="?" selected="selected"></option> and the selected value in the dropdown appears blank.

But if I then set my state s.t. my getOptions() returns that additional option:

...
$scope.selectedId = 3;
$scope.showThirdOption = true;
...

...I get an infinite $digest() loop.

errors loop bad

Is there a nice way of avoiding a problem like this? Do you think it's a bug in Angular (it is technically a regression), or is this just... not a way I should be using ngOptions?

~~~ Again, I have a nice Fiddle for you to play around with!! ~~~

Furrier answered 16/12, 2015 at 3:33 Comment(1)
Here's an example showing that this problem doesn't arise if your options are values instead of objects: http://jsfiddle.net/x15jccmj/3.Furrier
A
2

The error occurs because you call function getOptions() in ng-options. Create new variable and assign value returned by this function, then use it in ng-options:

$scope.newOptions = $scope.getOptions();

ng-options="opt.id as opt.label for opt in newOptions"

Also don't forget to update newOptions on button click.

Then you'll have no infinite digest. See updated fiddle: http://jsfiddle.net/bbcjeuhb/

Abduce answered 16/12, 2015 at 12:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.