13
May
2014

AngularJS on top of Drupal

AngularJS can be used along with, or more precisely on top of, Drupal fairly painlessly.

I've had a few occasions recently that called for a good deal of javascript to process and display data, and angular really is a great fit for that. Not only is angular a great fit, but since it's pretty painless to build up various content types in Drupal, and then query against those and prepare data to feed to an angular application, pairing Drupal with Angular has been productive, fun, and interesting.

You may or may not have heard it stated before that by and large, the vast majority of slowness on a Drupal site comes in the theme layer. My experiences align with that sentiment.  So while your first reaction to the notion of placing a custom angular app on top of a Drupal site may be something along the lines of "Oh, Drupal? It's so big, and slow.." that's not really the case usually, especially if you avoid the theme altogether for your data calls.

So, essentially what we're talking about here, is using Drupal as the backend data source, and AngularJS for presentation.  However, that's going quite a bit further than I've ventured with it.. I suppose, in theory, it would be possible to have an entirely angular powered front end to a Drupal site but that is far beyond the scope of what I'm talking about or have done.

Before I get any flaming comments, this post isn't going to really delve too deeply into the guts of making this work, it's more of a very high level view with a couple of helpful insights sprinkled in for flavor.

Alright, lets get on with it...

So, AngularJS, headed up by some really cool guys from Google, is hands down my favorite JS library/tool/whatever to come out in recent years. Like Drupal, it can take some doing to wrap your head around it but once you do it's really powerful, and really flexible. As with most any javascript based library, framework, whatever, it's painfully simple to consume JSON with Angular.

Lucky for us, it's also painfully simple to produce JSON data with PHP, and more specifically with Drupal.

Need a custom menu callback that will only spit out JSON and side step the rest of the theme layer? No problem, in your menu item definition in hook_menu() throw this nifty little nugget of greatness in there:

'delivery callback' => 'drupal_json_output',


What it does is instead of passing your menu callback's return value off to the normal Drupal theme layer is run it through PHP's json_encode() function, set appropriate response headers, spit out that json encoded data, and exit. MUCH faster than all the extra processing done in the theme layer to loop through arrays, render elements, etc. 

Angular's real strengths are in its two-way binding, and wicked-fast processing of data.. whether that is filtering, sorting, looping through, etc. It's just fast.

It's also very extensible, and has jQuery lite baked right in (not that that really matters when using it with Drupal, as you'll have full jQuery access since Drupal adds that to the page by default).

Many people may be unaware if they don't do a lot with javascript and Drupal, but Drupal exposes several of its helpful functions to javascript.  Notably, t() and formatPlural(). These work basically the same as they do in PHP.

Since I'm talking Angular & Drupal right now, I'll focus on t() and share the nice solution I came up with recently to leverage it within my angular app.  Obviously it's already available since it's part of the Drupal object in the global namespace on any given drupal 7.x+ site, but to access it within an angular scope it's nice to actually pull it into that scope so you can use it more easily.

Here's a sample angular controller that exposes the Drupal t() function within it as a local scope variable:

app.controller('MainCtrl', function($scope, $window) {
  $scope.t = function(str) {
    return $window.Drupal.t(str);
  };
});

The big thing there is injecting $window into your controller so that you can access the global Drupal object from within your controller. You could probably still access it anyway, since it is global after all, but this method leaves you with code that tests can be written for, since Drupal.t() could be mocked if necessary.

WIth that one can simply pass values through that local scope function, which in turn are passed off to the Drupal function, without having to include a bunch of weird scope syntax in the template.  So you can do things like this:

<p>By exposing Drupal's t() function to Angular, now we can have:</p>
<ul>
  <li>{{ t('Translatable Titles!') }}</li>
  <li>{{ t('Translatable form labels') }}</li>
  <li>{{ t(some_var) }}</li><!-- even translatable variable values! -->
</ul>

Neat, huh? 

There's lots more that can be done with Angular & Drupal together.  They're not a perfect pair, but they can, will, and do work together happily if you ask them to nicely. :)

Here's a couple of the things I've done recently with Angular on top of Drupal:
Autodesk product knowledgebase

Autodesk's recently launched knowledgebase website uses solr for it's search backend.  For various reasons, the front-end needed to be custom built. I was tasked with this portion of the project and opted to leverage Angular for its speed, both speed in development and speed in processing/display of data. The entire search system is a custom angular application that (indirectly, proxied through the Drupal backend, though all custom even there) queries the solr server for search results, and updates those results based on selected facets and sorting/filtering options. 

 



BRE Properties Floorplans & Availability

All of the Floorplans & Availability data uses Angular for presentation. There's a good deal of processing involved in the data preparation on the Drupal side, and actual availability data is pulled from a 3rd party daily for (at the time I built it) each property (looks like it's no longer all properties). To get a feel for how fast it is, select a different 'move in date' and watch the data update.  Note: Angular will happily update in place without removing all of those listing first, but since it can in some cases happen impossibly fast it was difficult to notice it had changed, so I included a switch to hide the floorplans during the update and reveal after update complete. 

* BRE has since changed their site and I don't believe any of my code is in use any more. However, the following has since come online... 
 


Custom calendars for Wizards of the Coast's: Magic The Gathering

The 'overview' and 'list' tabs are two different displays of the same data. Given the design, and timeline, Angular was a great tool to employ to get this piece of this site built quickly and on time/budget.


Have you worked with Angular & Drupal together? What sort of things are you building? I'd love to hear about it in the comments!