I have a couple of apps that make $http.get() calls and I wanted to be able to show a nicely formatted error message with ugly error details hidden, but accessible. Basically, this:
And then if the user clicks on the error, they see more info:
Simple stuff. Since the exact same potential error can appear in the administrative screen as well as the end user screen, it clearly called for a custom Angular directive. I found this outstanding series of articles (http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-i-the-fundamentals) by the great Dan Wahlin. Following his advice, I very quickly created a <hello-world> directive and moved on to my more complex error display squeegee. I ran into a bit of trouble with this more complex directive. Happily, sort of by chance, I had told WebStorm (the editor I use these days) that the JS file was an Angular file and it helped me figure out the issue. This is the code for the directive itself:
angular.module("CDLApp").directive("generalCdlErrorHandler", function() {
return {
restrict: "E",
replace: true,
scope: {
retrieveLastConfigurationError: "&"
},
template:
'<div class="alert alert-danger" role="alert" ng-init="doShowExpandedErrorDetails = true" ng-show="retrieveLastConfigurationError()">' +
' There was an I/O error or other error. This usually happens because configuration data file could not be ' +
' found or the configuration file contains inaccurate information (such as referencing a document library ' +
' that does not exist).' +
' <br/>' +
' <div ng-show="doShowExpandedErrorDetails">' +
' <a href="#" ng-click="doShowExpandedErrorDetails = ! doShowExpandedErrorDetails">' +
' Click here to hide details.' +
' </a>: ' +
' <br/>' +
' <pre>{{retrieveLastConfigurationError() | json}}</pre>' +
' <br/>' +
' </div>' +
' <div ng-show="!doShowExpandedErrorDetails">' +
' <a href="#" ng-click="doShowExpandedErrorDetails = ! doShowExpandedErrorDetails">' +
' Click here to expand error details.' +
' </a>' +
' </div>' +
'</div>'
};
});
Basically, I’m creating a new element called a “generalCdlErrorHandler”. It needs access to a function called retrieveLastConfigurationError and that’s handled in the scope object. I probably could have just used the parent’s scope, but that feels lazy. If anyone thinks I should have done that, I’d love to hear about it in the comments.
This was all fine, but I wasn’t getting anything. No errors popped up in the console (at least once I fixed all the sx errors I created along the way). I simply didn’t get any output from the directive. I went and added some static text before the ng-show directive and I *did* get that. This made me think that perhaps the directive wasn’t allowed to implicitly create new vars like “doShowExpandedErrorDetails” or have an “ng-init” in there.
I went back into the HTML to see if I had a type and this time WebStorm helped me out. I had been passing in the retrieveLastConfigurationError function like this:
<general-cdl-error-handler retrieveLastConfigurationError="CDLController.retrieveLastConfigurationError()">
</general-cdl-error-handler>
But it really needed to be this:
<general-cdl-error-handler retrieve-last-configuration-error="CDLController.retrieveLastConfigurationError()">
</general-cdl-error-handler>
WebStorm was smart enough to know that it had to be hyphenated. If it hadn’t provided that hint, I’d probably be still troubleshooting this . Fun times!
The trick is this: not only is the directive element name hyphenated, so are any attributes you add to it. Once I added the hyphens, it all worked great. Dan’s tutorial happened to use short single names, so I didn’t make the connection.
Hope this helps someone.
</end>
Follow me on Twitter at http://www.twitter.com/pagalvin