Trouble-shooting Tip For Angular Directives (Or, Learning To Love Hyphens All Over Again)

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:

image

And then if the user clicks on the error, they see more info:

image

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 Smile.  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>

undefinedSubscribe to my blog.

Follow me on Twitter at http://www.twitter.com/pagalvin

IE9 Really Doesn’t Like It When You Take A Shortcut With Your <span> Tags

I’ve fallen into a bad habit of using Chrome all the time.  It’s “bad” because the stuff I develop really needs to run on a lot of other web browsers, including, sadly IE8.  My work laptop has IE9 standard for whatever reason) and I was just doing a quick check to see what things looked like and … it wasn’t pretty.  For example:

image

It’s *supposed* to look like this:

image

 

Not only was it off, but my click events weren’t firing.  (Most of them, anyway).

Visually, it looked like things started to go off the rails near the “Advanced Setup” link.  I dug into that part of the HTML and found that I had this line:

<span class="glyphicon glyphicon-new-window” />

That seems like allowable syntax (“Chrome version 40.02214.94 m” is fine with it). I went and changed it anyway, as shown:

<span class="glyphicon glyphicon-new-window”></span>

That fixed it.

Such a tiny little thing caused such a huge mess of a screen.  Fun times.

This happened to be a quick fix, but it’s also the kind of thing that just gets your spine out of alignment when you see it.  There are over 500 lines of HTML in this little admin function and you just don’t want to find yourself digging amongst those weeds, ever Smile.

</end>

undefinedSubscribe to my blog.

Follow me on Twitter at http://www.twitter.com/pagalvin

HTTP 406 Error When Using Angular $http.get Against SharePoint REST End Points

Update: Marc AD ndersson pointed out this great piece of info: http://blogs.office.com/2014/08/13/json-light-support-rest-sharepoint-api-released/.  That explains a lot :).

That may be the worst title of a blog post ever!  Anyhoo.

I typically do all of my prototyping against an O365 instance.  I have my personal instance so that I don’t have to be worried about affecting anyone else.  As an aside – remember when we call carried around virtual machines on our laptops with MOSS – SQL Server, IIS, deciding Hyper-V vs. VMWare?  Anyhoo…

I had developed an app using Angular in this environment that does, among other things, this:

$http.get(serverUrl)
.success(function(data, status, headers, config) {

    var getLinksResponse = data;

    getLinksResponse.value.forEach(function(theResult) {

    // and so on and so froth

This was working just fine in two different SharePoint online environments.  However, when my colleague ported it to a Cloudshare instance, he was getting an HTTP 406 error (which was the first time I ever got that one, so … yay, I guess).  We did a bit of research and noticed that the “Accept” header was off.  SharePoint online was perfectly happy with:

Accept: application/json

But the cloudshare instance (which is SP on prem, hosted in a virtual server) wanted the classic “odata=verbose” added in as well:

Accept: application/json;odata=verbose

To fix that, we added the header as such:

var config = {headers: {
‘Accept’: ‘application/json;odata=verbose’
}
};

$http.get(serverUrl,config)
.success(function(data, status, headers, config) {

  var getLinksResponse = data;

  getLinksResponse.value.forEach(function(theResult) {

  // and so on and so froth

That got rid of the 406, but it also changed the format of the response.  It was more … verbose.  (haha!)  More changes were required and here’s the final result:

var config = {headers: {
‘Accept’: ‘application/json;odata=verbose’
}
};

$http.get(serverUrl,config)
.success(function(data, status, headers, config) {

  var getLinksResponse = data;

  getLinksResponse.d.results.forEach(function(theResult) {

  // and so on and so froth

This only turned into a 30 minute problem for us, so we lucked out.  Hopefully someone finds this useful.

</end>

How-to: Enable Multiple Angular SharePoint Web Parts on the Same Page

This blog posts describes how you can have multiple Angular.js based SharePoint web parts (referenced via a content editor web part) on the same page.  I’m calling a content editor web part (CEWP) that references JavaScript built using the Angular.js framework an “Angular Web Part.”

Angular’s bootstrap process is super easy and just about every example you find on the internets goes something like this:

<html ng-app=’myApp’>

  <blah/><blah/><blah/>

</html>

This breaks down, however, if you want to enable multiple CEWP’s representing multiple angular web parts on the same page.  Angular will only automatically bootstrap against the first ng-app directive it finds – at least as of angular version 1.3.6.  The solution is pretty simple – manually bootstrap your code instead.  The above now changes to something like this:

<body>
<d
iv id=”bootstrapHere” ng-controller=”myController as theController”>
<blah/><blah/><blah/>
</div>
</body>

<script src=”//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular.js”></script>

<script>
angular.bootstrap(angular.element(document.getElementById(“bootstrapHere”)),[‘myApp’]);
</script>

Basically, instead of using ng-app on the element to do your bootstrapping, you slap an ID onto that element.  Then, use the bootstrap() method on angular itself to control the bootstrapping process at run-time. I’ve tested this with three different Angular web parts on the same page and it works a charm.

</end>

undefinedSubscribe to my blog.

Follow me on Twitter at http://www.twitter.com/pagalvin

The New Jersey Motor Vehicle Commission Takes Another Victim

So, my son is a bit overdue obtaining his driving permit.  Yesterday, in mid morning, he trucks up to Oakland NJ to get it.  He gets there, fills out his paperwork is issued an unstamped permit and learns that he must now go to another MVC location to take his eye test.  Because, apparently, highly skilled eye testers don’t just live anywhere, so NJ MVC needs to go where the talent is.  Or, maybe it’s because they are following a Hamiltonian philosophy of consolidation?  Much as Hamilton felt financial and manufacturing consolidation were critical to the future economic strength of the Republic, maybe NJ MVC feels they need consolidate eye testing talent for the future strength of NJ MVC?  Maybe it’s part of an ineffable plan?  Alas, I have only questions on this topic and no answers. 

Following Oakland’s advice, wife and son truck their way down to Lodi, NJ with the unstamped permit to Lodi.  Lodi may have the worst parking of any NJ MVC location.  And, since they also host some of scarce yet highly coveted eye testing machines and eye testing professionals, they attract supplicants of all stripes, shades, education and gawkers.  My son works his way through the maze of lines and directions provided by the “never-look-them-in-the-eye” NJ MVC professionals and finally arrive at the eye testing line.  They now learn that the Oakland person made a mistake on the unstamped permit.  He mis-keyed the social security number, putting a an “8” in place of “2” in one of digits.  The NJ DMV person knew this because when she pulled up that wrong SS# in the computer, it didn’t show my son’s name.  Wife and son say, “oh, that’s the wrong number, you need a ‘2’ there instead of an ‘8.’”  What many, perhaps every single fair minded person would expect at this point is for the NJ MVC person to simply correct the number they just entered into the computer.  Ha! Fool!  No, instead he was asked to provided his social security card.  Let’s digress for a moment and consider that in order to get the unstamped permit in the first place, he had already provided a US Passport as well as a New Jersey birth certificate and letter written to him at his home address.   His mother is with him, shares his name, his address, his height (but sadly, not his taste in sci-fi movies) … you name it, my son is well and truly identified as life long resident of these US states and indeed, New Jersey itself by any measure you can imagine.  If the NJ MVC person would have simply fixed the mistake that the Oakland person made, the computer would have pulled up my son’s information and that would have been end of story.  But again, fool!  They can’t do that. Instead, the NJ MVC insist on a social security card now. 

So, wife and son go home to get it and return.  And in the end, he obtains his permit.

That’s three different trips to NJ MVC in one day.  To get his permit.  It took nearly 6 hours from start to finish.  This is my son’s introduction to driving in the Garden State.

NJ MVC is clearly broken. 

</end>

Angular Fails to Bootstrap in IE9

I’ve been playing around with Angular.js for the last long while and for the life of me, I could NOT get my Angular apps to launch in IE9.  They all work fine in IE11 but IE9 would just show the curly braces and similar bits.

I searched around and couldn’t find anyone complaining about his problem.  It worked fine in Chrome, IE11, just not IE9.

I was thrown off by the fact that the IE console was giving me errors like this:

SEC7111: HTTPS security is compromised by res://ieframe.dll/forbidframing.htm

That error had me thinking there was some problem downloading the angular or other libraries that I needed.  As it turns out, this was not the issue.

By poking around the internets, I finally found out that the phrase I needed to search for was “bootstrap” and that it seemed like the bootstrapping was failing.  In the end, my problem was that I had decorated my <html> tag with the ng-app attribute, as in:

<html ng-app="MatrixApp">

Well, that didn’t work for IE9.  Instead, I wrapped all the rest of the HTML in the <body> inside a div and references MatrixApp that way.

Problem solved.

Hopefully this saves someone some grief.

</end>

Creating Custom SharePoint Forms Without a Master Page

My colleague, Lauren Jones, wrote up a nice walk-through on how to create a custom data entry form using SharePoint Designer.  That’s not exactly “new under the sun” but there’s a bit of twist.  In her words:

Creating custom forms is straight forward to do in SharePoint Designer, navigate to your list and on the ribbon menu select ‘List Form’ and create your new form template.

This works well if you want your form to be attached to you master page, but what if you have the use case of creating a form that is in a popup window or is standalone without the SharePoint chrome. I had exactly this use case, I wanted to custom style a form then use that form in a popup div inline within a page.

Don’t despair, there is a way to do this which is not that intuitive but fairly easy to accomplish.

You can read all the details here: http://www.bigapplesharepoint.com/pages/View-An-Insight.aspx?BlogID=55&rtitle=customforms&rsrouce=pgblog and you can see it in action by clicking the “contact us for more information” link on any of the services on the services page of our Big Apple SharePoint site (http://www.bigapplesharepoint.com/services).

Lauren writes lots of good stuff on UX and branding.  You can see more of here writing here: http://www.bigapplesharepoint.com/team?showExpertName=Lauren%20Jones.

</end>

Distracting Design and Drunk on the Feature Coolaid

My colleague, Lauren Jones (https://twitter.com/laurenjones02) wrote up an short article talking about how overly complex SP rollouts are very hard on end users.  It’s sort of obvious, in a way, but it’s easy for me to say that after I’ve orchestrated a LOT of complex rollouts of things to unprepared end users over the years.

Here’s the key ‘graph:

Five years ago, when I rolled out SharePoint to an organization for the first time with a primary goal of becoming the collaboration platform and replacing share drives, we also introduced social and news feeds through RSS, My Sites and Profiles, and folksonomy tagging. Needless to say, this was a lot for end users to adopt in one swoop. While there was success with adoption around document management and profiles, RSS and tagging was less successful and this was really due to the change management communication and training. We couldn’t do it all at once. Taking the less is more approach and releasing functionality in phases is easier for end users to accept and adopt to.

This article reminds of another bit I read by Kris Gale related to Yammer’s feature set, “The One Cost Engineers and Product Managers Don’t Consider.”

If you have a horror story or success story to share, I hope you’ll do that in comments over on the Big Apple site.

</end>

Weekly Roundup – July 13, 2014

I for to xpost this here over the past weekend. 

Here’s the 3rd article in a series where I write about blog posts and online articles that were especially interesting to me in the last week or so.  This week’s entry in the series highlights two CodePlex projects for a potential InfoPath replacement and for managing permissions with SharePoint, news about satellites, yet another JavaScript framework and a nod to Ada Babbage and her role in computing history.

You can read it here: http://www.bigapplesharepoint.com/pages/View-An-Insight.aspx?BlogID=93&rsource=pgblog&rtitle=roundup

</end>

View CAML Queries in Real Time With ULS Viewer

My colleague, Ashsih Patel, wrote up a nice walk-through describing how to see the CAML behind various SP queries that happen in the course of business in real-time using the ULS viewer.

Here’s the intro:

Did you ever want to know what CAML queries are executed by SharePoint Server?

Well, for troubleshooting and learning purpose, it is not a bad idea. After all, SQL Profiler has been helping us troubleshoot a lot of issues.

There may be products out there but I figured out a way to do it without spending extra bucks! And here it is…

You can read the whole thing here: http://www.bigapplesharepoint.com/pages/View-An-Insight.aspx?BlogID=68&rsource=pgblog&rtitle=caml.

</end>