In my application, I have an input
field, and if the user enters a specific string (basically a string that matches a regular expression), a div
is displayed.
The (simplified) HTML part:
<div ng-app>
<h2>Todo</h2>
<div ng-controller="TodoCtrl">
<input type="text" ng-model="searchText"/>
<div>Hello</div>
<div ng-show="isValid(searchText)">World !</div>
</div>
</div>
and my controller :
function TodoCtrl($scope) {
var reg = /20\d{2}/g;
$scope.isValid = function(str) {
console.log('Is valid?');
return reg.test(str);
}
}
When the user enters a year (thus validated by the regular expression), I get the following error:
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [["isValid(searchText); newVal: true; oldVal: false"],["isValid(searchText); newVal: false; oldVal: true"],["isValid(searchText); newVal: true; oldVal: false"],["isValid(searchText); newVal: false; oldVal: true"],["isValid(searchText); newVal: true; oldVal: false"]]
http://errors.angularjs.org/1.2.1/$rootScope/infdig?p0=10&p1=%5B%5B%22isVal…2isValid(searchText)%3B%20newVal%3A%20true%3B%20oldVal%3A%20false%22%5D%5D
at http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.js:78:12
at Scope.$digest (http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.js:11472:19)
at Scope.$apply (http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.js:11682:24)
at HTMLInputElement.listener (http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.js:15653:13)
at http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.js:2562:10
at Array.forEach (native)
at forEach (http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.js:300:11)
at HTMLInputElement.eventHandler (http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.js:2561:5)
Here is a link to a JsFiddle: http://jsfiddle.net/U3pVM/6598/
What is wrong with my code, and how to enhance it?
It's the g
at the end of reg
. When you test the same expression on the same string twise, the second time it searches after what was found the first time. So, if you start with "2001.", the function will return true, then, called again, search the remaining "." and return false.
Here is another answer, explaining how it works.
You should use $watch
and a scope variable, instead of using the return value of a function to decide whether to show the element.
What happens is that this line:
reg.test(str)
Makes a change in str
which is a reference to the scope variable, which triggers another digest, causing an infinite loop. Edit: this is due to the regex having the global flag, as mentioned in another answer. So that combined with how angular's digest cycle works is causing it.
Here's the solution using $watch
:
function TodoCtrl($scope) {
var reg = /20\d{2}/g;
var isValid = function(str) {
$scope.show = reg.test(str);
}
$scope.$watch('searchText',isValid);
}
fiddle
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With