Here's a fiddle for illustration. When there's an ng-click directive that (for example) calls a function not defined on the controller's $scope (or its parents), it fails silently. When I'm trying to debug a webpage, this behavior is maddening, as a mis-typed function name can mean a lot of wasted time hunting it down. How can I find out when errors are being swallowed like this, and why is the answer "you can't?"
HTML
<div ng-app="AngularApp">
<div ng-controller="FooController">
<button ng-click="noError()"> noError() </button>
<button ng-click="error()"> error() </button>
<button ng-click="works()"> works() </button>
<br/>
<p ng-bind="foo"></p>
</div>
</div>
Javascript
var angularApp = angular.module('AngularApp', []);
angularApp.controller('FooController', ['$scope', function($scope) {
$scope.foo = 0;
$scope.works = function () {
$scope.foo += 1; // no error, everything works
};
$scope.error = function () {
$scope.foo += baz; // ReferenceError: baz is not defined
};
// noError is not defined in the controller, so errors suddenly don't matter?
}]);
Here's a fiddle for illustration. When there's an ng-click directive that (for example) calls a function not defined on the controller's $scope (or its parents), it fails silently. When I'm trying to debug a webpage, this behavior is maddening, as a mis-typed function name can mean a lot of wasted time hunting it down. How can I find out when errors are being swallowed like this, and why is the answer "you can't?"
HTML
<div ng-app="AngularApp">
<div ng-controller="FooController">
<button ng-click="noError()"> noError() </button>
<button ng-click="error()"> error() </button>
<button ng-click="works()"> works() </button>
<br/>
<p ng-bind="foo"></p>
</div>
</div>
Javascript
var angularApp = angular.module('AngularApp', []);
angularApp.controller('FooController', ['$scope', function($scope) {
$scope.foo = 0;
$scope.works = function () {
$scope.foo += 1; // no error, everything works
};
$scope.error = function () {
$scope.foo += baz; // ReferenceError: baz is not defined
};
// noError is not defined in the controller, so errors suddenly don't matter?
}]);
Share
Improve this question
edited Jun 20, 2020 at 9:12
CommunityBot
11 silver badge
asked Oct 7, 2014 at 2:12
Mark Joseph JorgensenMark Joseph Jorgensen
1151 silver badge5 bronze badges
1 Answer
Reset to default 9Why ngClick doesn't throw Reference errors on bad references
ngClick defaults to using $parse
under the covers. You can see that in the source here.
$parse is an angular helper function that parses angular expressions.
You can read about the rules for expressions in the documentation but the relevant snippet is below.
Angular Expressions vs. JavaScript Expressions Angular expressions are like JavaScript expressions with the following differences:
- Context: JavaScript expressions are evaluated against the global window. In Angular, expressions are evaluated against a scope object.
- Forgiving: In JavaScript, trying to evaluate undefined properties generates ReferenceError or TypeError. In Angular, expression evaluation is forgiving to undefined and null.
- No Control Flow Statements: you cannot use the following in an Angular expression: conditionals, loops, or exceptions.
- Filters: You can use filters within expressions to format data before displaying it.
How can you work around this?
The documentation then anticipates your objections and responds to them with
If you want to run more plex JavaScript code, you should make it a controller method and call the method from your view. If you want to eval() an Angular expression yourself, use the $eval() method.
So basically the idea is that expressions are for simple code, and any plex logic should be run from with a controller. In your case, you're not really doing plex things, just making bad references, but it seems like the answer to that from Angular's point of view is simply "be more disciplined" and structure your code to ensure your references will at least exist.
Why does it do it this way?
This has already been mostly covered, but in essence, expressions are meant to handle very simple logic, and are optimized for simplicity and not breaking your app. The idea is that anything that requires more extensive error checking can be handled in code.