An angular directive that refers to itself inside a template loaded separately causes an infinite linking loop, completely frying the browser. The page stays blank, and one cannot even open the development console to see the problem.
Working example
This directive foo works fine, because it never refers to itself recursively
1 |
|
Recursive example with inline template
Let us change foo's template to include a reference to itself
1 |
|
This simple example shows lots of "Hello from" on the same page until a JavaScript exception is thrown
RangeError: Maximum call stack size exceeded
at String.replace (native)
At least the browser stops the run away execution.
Recursive example with async template load
A more realistic example with a custom directive would keep its template in a separate file and access
it through templateUrl
. I always compile my templates using
grunt-html2js to prepopulate $templateCache
to avoid
separate Ajax calls
1 |
|
This simple page never shows anything! The Angularjs alternates between loading template and updating the DOM. Because these are separate operations through the event loop, and not a single JavaScript execution, the browser neither exceeds the maximum stack nor maximum single script execution time.
You cannot even see the problem or place a break point, even if you open the Chrome DevTools beforehand; the link function only executes once! The best strategy was to open the "Profiles" tab in DevTools and record a session on the unresponsive blank page. Then I could get an idea what the angularjs engine was spending time on. Here is a screenshot.
Notice the top 2 time sinks: setting node content and grabbing template's content.
Conclusion
Be careful when using directive's names inside the templates. This will cause infinite recursion that the browser does not stop. It can happen with cyclical dependencies too: if foo includes bar, and bar includes foo this can cause infinite linking loop.