Archive for the ‘AngularJS’ Category

AngularJS SPA

By:  Cole Francis, Senior Solution Architect at The PSC Group, LLC.

PROBLEM

There’s a familiar theme running around on the Internet right now about certain problems associated with generating SEO-friendly Sitemaps for SPA-based AngularJS web applications.  They often have two funamental issues associated with their poor architectural design:

  1. There’s usually a nasty hashtag (#) or hashbang (#!) buried in the middle of the URL route, which the website ultimately relies upon for parsing purposes in order to construct the real URL route (e.g. https://www.myInheritedWebApp.com/stuff/#/items/2
  2. Because of the embedded hashtag or hashbang, the URL’s are dynamically constructed and don’t actually point to content without parsing the hashtag (or hashbang) operator first.  The underlying problem is that a Sitemap.xml document can’t be auto-generated for SEO indexing.

I realize that some people might be offended by my comment about “poor achitectural design”.  I state this loosely, because it’s really just the nature of the beast.  Why?  Because it’s really easy to get started with AngularJS, and many Software Developers simply start laying down code that’s initially decent, but at some point they start implementing hacks because of added complexity to the original functional requirements.  That’s where they begin to get themselves in trouble very creative. 🙂

If you think I’m kidding, then just try Googling the following keywords and you’ll see exactly what I mean:  AngularJS, hash, hashbang, SEO, Sitemap, problem.

SOLUTION

So, the first step is to remove the hashtag (#) or the hashbang (#!).  I know it sucks, and it’s going to require some work, but let me be clear.  Do it!  For one, generating the Sitemap will be much easier, because you won’t need to parse on a hashtag (or hashbang) to get the real URL.  Secondly, all the remediation work you do will be a reminder the next time you think about taking shortcuts.

Regardless, after correcting the hashtag problem, you still have another issue.  Your website is still an AngularJS SPA-based website, which means that all its content is dynamically generated and injected through JavaScript AJAX calls.

Given this, how will you ever be able to generate a Sitemap containing all your content (e.g. products, catalogs, people, etc…)? Even more concerning, how will people find your people or products when searching on Google?

Luckily, the answer is very simple.  Here’s a little gem that I recently ran across while trying to generate a Sitemap.xml document on an AngularJS SPA architected website, and it works like a charm:  http://botmap.io/

I literally copied the script on the BotMap website to the bottom of my shared\_Layout.cshtml file, just above the closing tag.  This gives BotMap permission to crawl your website.  After doing this, push your website to Production, then point the BotMap website to your publicly-facing URL, and finally click the button on their website to initiate the crawl.  One and done!

BotMap begins to crawl and catalog your website as if it was a real person browsing it. It doesn’t use CURL or xHttp requests to determine what to catalog. The BotMap crawler actually executes the JavaScript, which is how it ultimately learns about all of the content on your website that it will use to construct the Sitemap.  

This is why it’s so great for websites created using AngularJS or other JavaScript frameworks where content is injected inside the JavaScript code itself.  Congratulations, {{vm.youreDone}}!

Thanks for reading, and keep on coding!  🙂

Advertisements

AngularJS.png

Author: Cole Francis, Architect

BACKGROUND

While you may not be able to tell it by my verbose articles, I am a devout source code minimalist by nature.  Although I’m not entirely certain how I ended up like this, I do have a few loose theories.

  1. I’m probably lazy.  I state this because I’m constantly looking for ways to do more work in fewer lines of code.  This is probably why I’m so partial to software design patterns.  I feel like once I know them, then being able to recapitulate them on command allows me to manufacturer software at a much quicker pace.  If you’ve spent anytime at all playing in the software integration space, then you can appreciate how imperative it is to be quick and nimble.
  2. I’m kind of old.  I cut my teeth in a period when machine resources weren’t exactly plentiful, so it was extremely important that your code didn’t consume too much memory, throttle down the CPU (singular), or take up an extraordinary amount of space on the hard drive or network share.  If it did, people had no problem crawling out of the woodwork to scold you.
  3. I have a guilty conscience.  As much as I would like to code with reckless abandon, I simply cannot bring myself to do it.  I’m sure I would lose sleep at night if I did.  In my opinion, concerns need to be separated, coding conventions need to be followed, yada, yada, yada…  However, there are situations that sometime cause me to overlook certain coding standards in favor of a lazier approach, and that’s when simplicity trumps rigidity!

So, without further delay, here’s a perfect example of my laziness persevering.  Let’s say that an AngularJS code base exists that properly separates its concerns by implementing a number of client-side controllers that perform their own genric activities. At this point, you’re now ready to lay down the client-side service layer functions to communicate with a number of remote Web-based REST API endpoints.  So, you start to write a bunch of service functions that implement the AngularJS http directive and its implied promise pattern, and then suddenly you have an epiphany!  Why not write one generic AngularJS service function that is capable of calling most RESTful Web API endpoints?  So, you think about it for a second, and then you lay down this little eclectic dynamo instead:



var contenttype = 'application/json';
var datatype = 'json';

/* A generic async service can call a RESTful Web API inside an implied $http promise.
*/
this.serviceAction = function(httpVerb, baseUrl, endpoint, qs) {
  return $http({
    method: httpVerb,
    url: baseUrl + endpoint + qs,
    contentType: contenttype,
    dataType: datatype,
  }).success(function(data){
    return data;
  }).error(function(){
    return null;
  });
};

 
That’s literally all there is to it! So, to wrap things up on the AngularJS client-side controller, you would call the service by implementing a fleshed out version of the code snippet below. Provided you aren’t passing in lists of data, and as long as the content types and data types follow the same pattern, then you should be able to write an endless number of AngularJS controller functions that can all call into the same service function, much like the one I’ve provided above. See, I told you I’m lazy. 🙂



/* Async call the AngularJS Service (shown above)
*/
$scope.doStuff = function (passedInId) {

  // Make a call to the AngularJS layer to call a remote endpoint
  httpservice.serviceAction('GET', $scope.baseURL(), '/some/endpoint', '?id=' + passedInId).then(function (response) {
    if (response != null && response.data.length > 0) {
      // Apply the response data to two-way bound array here!
    }
  });
};

 
Thanks for reading and keep on coding! 🙂

AngularJSTypeAhead2

Author: Cole Francis, Architect

THE PROBLEM

So, I ran into an interesting little challenge a couple of days ago. I was experimenting with some AngularJS code that would eventually be tasked with using SharePoint JSOM REST API’s to interact with various document libraries hosted in both SharePoint and OneDrive. I was chiefly interested in implementing a client-side, “type-ahead” filtering solution, meaning one that filters on the entire array of records that are returned from the SharePoint server.

Unfortunately, due to a staggering number of records being returned from SharePoint, some serious performance degradation issues arose. In several cases, it was taking the server well over a minute to return 10,000 rows to us. To address the lag time, we pared down the data to only include the attributes of interest to us. This helped, but the server was still far too slow.

After brainstorming with the rest of the team, we decided that server-side filtering was worth a shot. Bear in mind that “type-ahead” filtering can be extraordinarily slow on the server, particularly if the GET calls are summonsed on a “keystroke-by-keystroke” basis. For example, if your very first keystroke happens to be the letter ‘s’, then you should expect to return every file name with the letter ‘s’ in it, and with that goes a sizable chunk of your time and the server’s resources.

Likewise, if the next letter you type happens to be an ‘h’, the combination of the ‘s’ and the ‘h’ will cause the filter to run a little bit quicker than just a single character. But, the query would still take considerable time to complete, and the results will still be overwhelming and therefore useless to you.

Obviously, adding additional characters to your search string will continue to pare down the results and improve the server’s response time. But, when it all boils down to it, you don’t really care about returning results for things like ‘s’, ‘sh’, or ‘sha’. You actually only care about returning the results for the word ‘shazam’.

THE PROPOSED APPROACH

With this in mind, our proposed approach is to streamline the query attempts against the SharePoint server by only submitting SharePoint GET requests when user has gone without modifying their search text for an arbitrary amount of time. I’ll use 1500 milliseconds, or 1.5 seconds, in my upcoming code example.

One underlying benefit of this approach is to provide a user ample time to type in a search term, as well as give them time to make modifications to it and correct any misspellings, before initiating a GET call to the SharePoint server’s REST API stack. Another benefit is that it presents the user with an illusion that “type-ahead” filtering is actually taking place, when in fact it isn’t. The impact of this approach leads us to our overall objective, which is minimizing the number of calls to the SharePoint server and yielding more pertinent and smaller result sets back to the client application.

APPROACH CAVEATS

Unfortunately, building a sophisticated “type-ahead” solution in JavaScript isn’t always as easy as it sounds. Depending upon the functional and non-functional requirements, it can quickly become very challenging. In our case, we’ll need to keep track of the “onkeypress” or the “onkeyup” events that are tasked with alerting JavaScript functions to take some action on the SharePoint REST API’s.

Next, we’ll need a mechanism that evaluates whether or not there has been 1.5 seconds of inactivity on the model before executing the target function, but this only applies if there have been changes to the model. What’s more, if user modifies the model within the 1.5 second threshold, then the expiration slides another 1.5 seconds before the next SharePoint REST call can be made. But, none of this should occur if the model is either null or empty. As you can see, the more I discuss it, the more complex the functionality becomes.

THE SOLUTION

Alas, bring on AngularJS! It provides us with a very simple OOB solution that tackles this exact problem. In fact, everything I just mentioned can be brought to fruition by combining the following few lines of HTML, AngularJS, and JavaScript code:


<!-- Leverages AngularJS model-options to achieve the results we're after-->
<p>Server-side search filter.  Enter search filter here: <input type="text" text="" ng-model="delayedSearchFilter" ng-model-options="{ debounce: 1500 }"  /></p>

 
// Performs a delayed search per the model-options debounce value
//
$scope.$watch('delayedSearchFilter', function(nVal, oVal) {
     if (nVal !== oVal) {

          if ($scope. lastURI!= "" && $scope.lastName != "") {
               $scope.getSPOneDriveFiles($scope.lastURI, $scope. lastName, true);
          }
     }
});

Wow! Do you think you can handle all of that? Seriously though, that’s the solution in a nutshell. Everything I just talked about is now in play using the skillfully applied and illusory techniques I shared with you in the code example above. What’s more, I can easily explain the functionality to you in two simple bullet points:

  • Debounce: 1500Part of the AngularJS ngModelOptions, this directive tells AngularJS to update the model value using the number of milliseconds provided. In this case, I’ve specified 1500 milliseconds, or 1.5 seconds.

  • $scope.$watch(‘delayedSearchFilter’, function(nVal, oVal) This method signature subscribes to the ‘delayedSearchFilter’ model and gets invoked every 1500 milliseconds (or whatever the debounce duration is set to) if there are changes to the delayedSearchFilter model. I should point out that this function doesn’t fire when the model is empty or if the model hasn’t changed since the last time the function was invoked. How incredibly convenient is that? It’s like they read my mind!

From my perspective, the team at Google has probably spent a staggering amount of time and money on both maintaining and perfecting the AngularJS Framework. Additionally, I surmise that a large number of developers, many who are far more talented and smarter than I am, have contributed their IT prowess to the AngularJS Framework. These things being the case, why in the world would I ever want to write my own functionality to tackle this problem when I can simply leverage their proven work?

In the end, my custom JavaScript code might take some time to write, it might be error-prone, and it might require additional changes over multiple test cycles in order to make it production worthy. But, by leveraging the AngularJS Framework’s OOB built-in functionality the way it’s intended to be leveraged, I’m able to markedly decrease my development time while simultaneously increasing the probability of writing bullet-proof code on my very first attempt, which makes this a win-win solution for everyone!

Thanks for reading and keep on coding! 🙂