I hit an interesting problem yesterday with AngularJS views. They (the views) where working when clicking on a link, but not working when accessed directly, or when the back button was used (which broke the idea of AngularJS routing, since it is supposed to handle those to key scenarios).
After quite a bit of debugging, I was able to track the problem to the fact that if I placed the ng-view directive inside another directive, the refresh and back button would break (although it would work ok for links and direct browser url manipulation).
What is really nice, is that I was able to use the .NET C# based Unit Test infrastructure to confirm this problem and test for it :)
The code set-up
Here is the (simplified) pages/code that I created to test/confirm the issue.
The default.html page loads up the AngularJS includes and uses the custom views directive instead of the native ng-view directive (see highlighted line below):
The users.html page loads up the AngularJS includes but uses the native ng-view directive
The custom views directive is mapped on the directives.js file and it is a simple templateUrl mapping:
The views.html (mapped to the views directive shown above) contains the native ng-view directive
The route.js contains a test mapping to a specific view (in this case test.html). Note that this mapping exist on both route.js files (the one used by default.html and the one used by users.html (shown below))
The topMenu.html view (mapped to the custom topMenu directive on directives.js) provides a link to the test route (via an href to #/test )
Finally the test.html page contains just a little html (to provide a visual clue and ‘unit testable’ page change)
The problem
With the code shown above, this is what happens:
1) if when opening up the http://localhost:3187/tbot_v2/default.htm#/ page
2) … we click on the test link
3) … the test page will show up
4) If we manually change the path (i.e. enter the AAAs shown below and press enter on the location bar), we will get the 404 page (mapped via an .otherwise mapping)
5) If we remove (also manually) the extra chars (and press enter), it will work
6) But if we hit refresh now
7) … it will not work (i.e the route events don’t fire and the view is not rendered):
8) The same scenario happens if we open another page and hit the back button:
9) and the worse scenario is the fact that if we open the link in a new window, it will not work:
The solution
As mentioned before, after a while, I tracked the problem to the fact that in the default.html page I did 'one refactoring too many', and AngularJS doesn’t seem to fully-support the cases when the native ng-view directive is placed inside a custom directive (which is the refactoring that I was trying to do).
To confirm this, if we open the http://localhost:3187/tbot_v2/users.htm#/test page in a new window (which is using the native ng-view directive inside the main html page), the AngularJS routing events will trigger and the test.html view will be shown:
This page is also working for the back button.
UnitTest using VisualStudio, NCrunch and FluentSharp.WatiN
To test this behavior I used wrote the following UnitTest in VisualStudio:
To see it in action, lets add a script_IE_WaitForClose(); instruction to the end of the script:
… which will open an O2 Platform REPL script environment with the current WatiN IE object:
Note that from here we have full access to the IE object, and are able to use the FluentSharp.WatiN extension methods.
For example here is how to access the current links:
Update: See AngulaJS Issue 6812 for my report to the AngularJS team (note that this might not even be a bug, since it could be the expected behaviour of AngularJS routes and the ng-view directive)