An Introduction

AngularJS is the proclaimed “superheroic JavaScript framework.” I was turned onto Angular a little over six months ago with mild curiosity. I found it interesting, but never really had a reason to need it, as all our websites lately have been self contained. After all, Drupal and WordPress come with a well-developed theme layer. Even frameworks like Yii and Symfony include some concept of templating that do an acceptable job. Why would we bother to recreate a front end when one is already available? Increasing popularity just does not justify usage. Have a look at the recent trend data:

Angular vs drupal vs wordpress vs DNN vs symfony

Then, we came upon a site that required a front end and an application (IOs for now, Android later). I finally had a choice. We could write the app to communicate directly with the backside of some front end website. Or we could create an independent front end that utilizes the client’s browser for all the display logic, just like the application. That might sound like you’re duplicating efforts. But you really are not. Any IOs or Android app will have to handle layout, design, animation, etc., itself. All it needs is an API. What that API has to do is your real question. Is it appropriate for the API to be the front end?

We selected Drupal as our API, mostly due to familiarity and some support modules matching the features we needed with a pre-built API (services) layer. What made the decision to use the theme layer, or to create an Angular site for us was the desire for speed. The IOs app doesn’t need Drupal to know how to render pages. Any code added to the API site relating to display could potentially just reduce response times. If we were really careful, we could have avoided that, sure. But, why add anything while having to focus on avoiding issues? Instead, we have an opportunity to offload rendering and processing to a distributed network of clients. That and, well, it was fun to experiment with something new.

What is Angular?

For those who are unfamiliar Angular, I’d like to give a brief review of its concepts. In an interview with Paul Krill, Misko Hevery of Google, the founding co-author of AngularJS,  described some of what he considered selling points. Feel free to read the full transcript, but I’ve pulled out some of what I found meaningful:

… we have dependency injection, which is very unique. Nobody else has that. But I think that the thing that really hits it home for people is that we have this idea of a directive

Misko Hevery

… We take HTML, which is really good at static documents, and through this concept of directives, we add new markup to HTML that turns static content into dynamic content. Hence, we say it's the HTML-enhancer

Misko Hevery

… Angular was meant for the form-based Web.

Misko Hevery

Those quotes, however, fail to explain what exactly Angular is all about. So, here’s an overview of selling points from my perspective, in order of importance:

  1. Angular removes page reloads. This provides benefits to end users in smoother transitions, smaller network requests, and a more responsive experience. It’s hard to overstate the benefit of end-user smoothness to satisfaction. It also reduces the amount of data that has to be transferred to—or processed by—the server. The entire theme layer is moved off the server.
  2. Nearly every permeation of the user and application state can be handled without reload through the client just by setting a scope variable.
  3. It’s a fully functional framework that allows you to build complex web applications, without a beefy server to render the pages. All you need is some JSON.
  4. The end user gains additional performance, as nearly every ‘heavy’ component you would use (Angular.min.js, bootstrap.min.js, jquery.min.js, etc.) can be pulled off the most popular public CDNs (google’s and maxcdn). That means all the end user has to do to render your website is download tiny app.js files on demand. Nearly the entire shared codebase and theme-rendering engine has a good chance of already being cached in the user’s browser.
  5. Ready for full crazy performance boost? Angular is nothing but flat files. You can serve the entire site 100% from a CDN, if you like.

What’s the common thread in all of this for me, you ask? UI, experience, and performance. The end user. Angular has been billed as a “front end developer’s” tool, but I don’t agree. We did have a developer with strong JS/CSS/HTML experience on this project. He enjoys the html templating system, but it was not built for him to create an entire site on his own. The limitations he ran into on multiple occasions put building the site out of his reach. In the end, programming a complex application in javascript is just as complex as any other language, maybe even more so.

Angular is confusing — because we are indoctrinated.

Because Angular is relatively new, there just aren’t as many good tutorials out there as I would have liked. The reviews are primarily about frustration and confusion, turning into hate or love. Small snippets of code to illustrate fringe concepts seem to be lacking on search results for now as well.

Perhaps the most amusing review I saw came from Ben Nadel. His initial thoughts were nothing but this glorious image, which mirrors my own experiences:

But in the comments, as he relates more directly to his readers’ questions, there are some high notes:

One thing that is great is that the Google Group for AngularJS is very active; and, the core team members actually respond to almost all of the messages posted. It's pretty amazing!

There's definitely a bit of a learning curve, especially if you come from a heavy jQuery background (like I do) – you have to start to think differently about how you interact with the DOM. But, it's very powerful.

I, personally, have not acted in that group. I can’t comment on that, but it was very heartening to hear. His second note is the real meat of the situation. In preparing this entry, I reviewed a few of the top results for ‘Angular reviews’ and the confusing was obvious. Perhaps one of the most ‘vigorous’ posts I saw was from George Butiri. His suffering through the process of learning was obvious, and likely will sound similar to your own:

The main reason Angular JS will fail is because it’s difficult.

For me, Angular has failed for the following reasons:

  • No clear examples of the two most widely used front-end features, DOM Manipulation and AJAX calls.
  • Most of my development (over 99%) consists of those two features.
  • jQuery easily provides AJAX calls, and keeps the code lighter and cleaner than Angular.
  • Even Angular documentation suggests you use jQuery for DOM Manipulation.
  • Why even bother using Angular if most of my work consists of features easily implemented by jQuery?

I found perhaps the most interesting lines of his entire post to be these two quotes:

AJAX can be done by both, fairly easily. So that’s not a problem. … As far as making things easier … well, the shortest road is the one best known.

Frameworks suck.

His vitriol and specific gripes serve to illustrate the point I’m trying to make. Angular is not a javascript plugin library. It’s not a ‘simpler’ or ‘more enjoyable version’ of javascript. You can’t just say, “I’ll find a plugin,” as many front-end workers do. It’s not that sort of animal. It’s an entire framework that requires overall experience with concepts more common to backend developers such as: dependency injection, request lifecycles, menu routing, services, and event broadcasting. If you’re familiar with those concepts, you’ll be in a far better place when starting your adventure.

You will, however, run into the problem that Ben Nadel pointed out about having to rethink how javascript is meant to interact with the document. I’ve built some pretty wild single page applications through a light html load, and heavy DOM manipulation using jQuery. Backing away from that approach, and switching to templates requested on demand with nothing but {{ curly_braced_data }} caused me some shock. Prebuilding all the permeations possible into the html, with nothing but ng-show or ng-hide conditions took me a long time to get used to. I was completely weirded out by the data bindings; I kept wanting to code jQuery(‘#field_1’).val() to get things, but it just isn’t needed. For a very good write-up on differences in thought patterns, check out this question on stack overflow.

And someday, you may eventually reach the point where what you need to do simply does not work well only through Angular. For me, it was drawing the teams into the regional brackets, with dom based traversal for data gathering before posting a picked team to the server. I ended up going back to what I knew: jQuery for that one job. Only later did I find out that Angular actually ships with a built-in version of jQuery lite! I have not yet gone back to figure out if that would have been enough to do the job, but I think it might be.

Lessons Learned

Looking back at things I ended up having to rewrite, or decided were just not good enough, I think I might be able to help you avoid making the same mistakes. These represent of some of my worst, confusing, and best solutions. I’m not certain they are right, but I stand by my decisions until someone shows me better.

1. Organize your project by feature

There were a metric ton of suggestions about how code should be organized. Loads of people seem to support a traditional MVC separation, with controllers and templates in different sections. I just could not figure out why. While bringing in other developers at the last minute, I found this sort of layout made things easiest for them to grasp and immediately start working:


root
app
  core
  app.js (primary file Angular file)
  directives
    1,2,3.js
  common.css
feature_1 (users)
  login
    controller.js
    index.html
  logout
    controller.js
    index.html
  profile
    edit
      controller.js
      index.html
    controller.js
    index.html
  users.css
feature_2, etc.
assetsĀ 
  libraries
    Angular plugins, jquery plugins, etc.
bower_components, etc

2. Create tons of small files

Nothing sucks like debugging javascript files in the 1000+ line area. There’s just no reason to have that kind of awful. As you start really digging in to build with Angular, you’re going start having a lot of css and js files. And that is a good thing. Don’t worry about it. You only have to follow two rules:

  1. Lazily load any controller and template files you can on demand using the UI Router.
  2. Use a task manager like grunt to clean up your swarm of files into just a couple during deployment.

There is a solid guide on how to best serve your files over at http://stackoverflow.com/questions/21099528/multiple-files-on-cdn-vs-one-file-locally. It breaks down to:

  1. Common libraries (Angular, jQuery, Bootstrap) belong on their owners’ CDNs.
  2. Library files, like plugins for Angular and jQuery belong in another rarely changing file.
  3. Core logic belongs by itself on a somewhat short timeout, or a versioning system.

3. Think of replacing entire sections of the site with entire other templates

This one took a bit more imagining to make happen. I’ll try to walk through the components:

Index.html

No real header, footer, navigation, or page html sits in index.html. Instead, we use the include power of Angular to fetch templates to insert inside our slots by simply providing a url to fetch:

<main id="main" ng-include="Page.mainUrl">...</main>

Note that I did not specify a hard coded url. I used a variable of the “Page” object instead.

In app.js (the main js file), I exposed the Page object to the scope in the main controller:

Controllers

Meanwhile, the Page object defines an initial set of parameters, but it can be provided to any controller and then update them and the page itself:


app.provider('Page', function() {
  var defaults = {
    title: ''
    ,headerUrl: 'app/layout/templates/header.html'
    ,mainUrl: 'app/layout/templates/main-constraint.html'
    ,footerUrl: 'app/layout/templates/footer.html'
  };
  var settings = Angular.copy(defaults);

  return {
    $get: function($rootScope) {
      // We probably want to revert back to the default whenever
      // the location is changed.
      $rootScope.$on('$locationChangeStart', function() {
        Angular.extend(settings, defaults);
      });
      return settings;
    }
  };
});

app.controller('mainCtrl', function(
  ,Page
  ,...
){
  ...
  Page.mainUrl = 'app/layout/templates/main-without-constraint.html';
  ...
}

In this way, the mainCtrl is able to swap from a constrained width template for the main content to a screen width main area, and the UI-Router will fetch the content of the home template into our expanded area. On the next page change, everything resets.

4. Domain Cookies are a problem

This one frustrated me, greatly. It turns out Angular’s cookie objects are a bit too strict on the domain you have to use when creating a cookie. I needed a top-level cookie since it has to post to api.bigshotbracket.com during AJAX requests. While it’s not hard to create the required cookie through JS manually, it sure wasn’t obvious I’d need to do so at first. Save yourself time. Create cookies through your own code. Use the cookie management dependencies for using them only.

5. Any code that might be called asynchronously should be run through $timeout.

Some of initial documentation I found for handling AJAX requests acted like it would be enough to alert the $scope by just setting a variable. Eventually, I figured out that often won’t cut it, as any delay in processing might unhook the $scope’s monitoring. To that end, I started using $scope.$apply, which is designed to wake the scope up. That avenue also had an issue. If I was running multiple things at once, I’d reach conditions where multiple requests would complete at once, and the scope was already digesting the previous changes, causing it to refuse any more. The answer is $timeout, with a delay of 0. You can abuse it like your own personal little processing queue for $scope.$apply!


$timeout(function(){
  jQuery('html, body').animate({scrollTop : 0}, UX.settings.animations.scrollTop.timing);
}, 0);

[more]

Closing Thoughts

AngularJS is amazing… and hard as hell.”

Jose Jesus Perez Aguinaga – https://coderwall.com/p/3qclqg/Angularjs-is-amazing-and-hard-as-hell

I’m almost with Jose on this one. Learning Angular ate a ton of time. I went in expecting that. I did not expect to still be rewriting my mistakes for the next three months. Maybe I was just overly optimistic? The more I forced myself to think in terms of singleton services and objects being passed around to controllers and a persistent document, the easier Angular got. I’ll admit that writing my own directives took some black magic I still don’t fully understand. Then again, I didn’t have to. After a while, I started to ignore the ‘why’ and ‘how’ of Angular’s internals. At no point did I ever have to wonder why databinding worked, or the directive performed. It just worked. I felt the same way about the loose interpretation of values. It’s almost like someone took the easy mode button of php’s empty() out to javascript.

In the end, Angular cost me something like an extra 30-40% to learn in hours for the project. But, it also sped up simple interactions like form data over the course of the project so much, I’m tempted to call it a wash! The parts that really ended up costing our team time was getting performance tweaks into the system: grunt to manage the load of tiny files, cdn usage on production only based on url, etc.

I fell in love with having no document reloads, with having things just work that used to be time consuming in javascript, and being able to manipulate the site simply by setting a variable. I fully intend to keep working with Angular. I’m open to any project with it, so long as there’s a good API for me to program against. I’ll be attended a local streaming party of the Angular 2.0 conference on March 5th and 6th. The upcoming feature performance gains in 1.4 are very promising, with minimal upgrade work. Moving from 1.4 to the new routing system, web components, and immutable objects of 2.0 will be a major undertaking. The gains to be made though… Amazing. From the demos I saw, you can achieve gains of more than ten times the speed! Look forward to that, and many more goodies. Keep an eye on https://angular.io/ for 2.0 news!


 

Let's Get Started