Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why don't AngularJS errors in the html show up in the console?

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?
}]);
like image 373
Mark Joseph Jorgensen Avatar asked Oct 07 '14 02:10

Mark Joseph Jorgensen


1 Answers

Why 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 complex 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 complex logic should be run from with a controller. In your case, you're not really doing complex 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.

like image 83
Ben McCormick Avatar answered Sep 29 '22 19:09

Ben McCormick