AngularJS: Using dynamic content with $compile

One of the more opaque concepts about AngularJS is the process that converts a chunk of HTML from a template into “Angularized” HTML which is then inserted into the DOM. During this conversions, custom directives are replaced with their corresponding HTML content, Angular directives like ng-repeat are processed, and any event handlers of interest are wired up. As it turns out, Angular’s $compile service is what’s responsible for making the magic happen. OK great, but why is this interesting or important? Because leveraging the $compile service directly lets you take dynamic content and process it to enable Angular directives and behaviors.

Since examples are always helpful, here’s an admittedly contrived one that we’ll walkthrough. Imagine that we’re building a WordPress slideshow plugin and we want to support custom themes for individual slides. So in our plugin, a user would be able to modify the HTML that displays a slide, we’d save it to the database, and then retrieve that template when we render the slides. For arguments sake, let’s assume the “default” template for the slideshow looks something like this:

<div ng-class="slide.isActive ? 'active slide' : 'slide'">
  <slide-image ng-src="{{ slide.imageSrc }}"></slide-image>
  <div class="description" ng-bind="slide.description"></div>
  <starbar config="slide.starConfig"></starbar>
</div>

As you can see, we’ve got a few directives and by default we’re displaying some description. Generally, we could set this up by creating a “slide” directive that looks something like:

angular.directive('slide', function(){
    return {
      restrict: 'E',
      scope: {slide: '='},      
      templateUrl: 'slide.html',
    };
});

Great, nothing to crazy but with this setup there’s no way to supply dynamic HTML from our database to use in the template. In order to allow a custom template you’d just need to modify the directive to look something like:

.directive('slide', function($sce, $compile){
  return {
    restrict: 'E',
    replace: true,
    scope: {slide: '='},
    template: "<div></div>",
    link: function(scope, el, attr){
      angular.element(el).html(scope["slide"].template);
      $compile(el)(scope);
    }
  };
})

And then you’d be able to use it with:

<slide slide='config'></slide>

/** Javascript **/
$scope["config"] = {
  "template": "<h3 style='color: red; font-weight: bold' ng-bind='slide.description'></h3>",
  "description": "hello world!",
};

The key difference is that in the modified directive the template is inserted into the directive’s element using “angular.element(el).html(scope[“slide”].template);“ and then finally the $compile service is invoked to process the regular HTML to get Angular magic.

Anyway, as always questions or comments welcome!

Setfive: Looking back on a summer of shenanigans

Labor day has come and gone so summer is officially over. We sat down with our intern Phil to chat about his time interning at Setfive.

Favorite Part About Interning At Setfive?

My favorite part about interning at Setfive was being introduced to so many different programming tools, and having the ability to increase my programming skill set. This summer I learned about PHP, the Symfony 2 Framework, MYSQL, I improved my JavaScript skills, learned some Angular.js, and even learned how to write unit tests. I was exposed to so many new things that everyday was fun and no two days were ever the same.

The environment here encouraged questions, and allowed me to ask and receive answers to anything I wanted to know more about. Some of the guys would even go out of their way to send me related documentation about something if they felt that they couldn’t confidently answer it themselves.

Working under the guys here was an incredible experience, I was given the freedom to make mistakes and figure out problems on my own, but at the same time was given sufficient structure to make consistent progress. It was awesome to have the comfort of knowing I had a smart, qualified person to guide me in the right direction if I ever got too stuck on any one problem.

Most important thing that you learned?

The most important skill that I learned was definitely an improved conceptual understanding of MVC, and that while sometimes using this pattern slows down your programming, in the long run it helps you create readable, modular code.

I also learned that installation is just the worst.

Most Memorable Moment?

The most memorable moment of the summer was the first time we used the Txty Jukebox in the office. It didn’t quite work the first time around, however, watching people use and get enjoyment out of something that I helped to create was something that I’ will never forget.

Where do you want to go from here?

From here I definitely want to continue building custom applications. I’ve spent the last part of the summer teaching myself objective-c, and the skills that I’ve learned here will definitely help me make the transition into developing iOS applications.

Top 5 Things To Eat

  1. Buffalo Soulja - Darwins (Only available on Thursdays)
  2. Mango Bubble Tea - Dosa Factory
  3. Steak Sammy - Orinoco
  4. Burger topped with shortrib meat – Charlies Beer Garden
  5. Chicken Pad Thai - Thelonious Monkfish
  6. Honorable Mention: Cuban Sammy - Plough and Stars

Making Doctrine and Symfony Logged Queries Runnable

On many of our projects we use Gearman to do background processing. One of problems with doing things in the background is that the web debug toolbar isn’t available to help with debugging problems, including queries. Normally when you want to see your queries you can look at the debug toolbar and get a runnable version of the query quickly. However, when its running in the background, you have to look at the application logs to see what the query is. The logs don’t contain a runnable format of the query, for example they may look like this:

SELECT 
  t0.username AS username1, t0.username_canonical AS username_canonical2, t0.email AS email3, 
  t0.email_canonical AS email_canonical4, t0.enabled AS enabled5, t0.salt AS salt6, t0.password AS password7, 
  t0.last_login AS last_login8, t0.locked AS locked9, t0.expired AS expired10, t0.expires_at AS expires_at11, 
  t0.confirmation_token AS confirmation_token12, t0.password_requested_at AS password_requested_at13, t0.roles AS roles14, 
  t0.credentials_expired AS credentials_expired15, t0.credentials_expire_at AS credentials_expire_at16, t0.id AS id17,
  t0.first_name AS first_name18, t0.last_name AS last_name19
FROM app_user t0 
WHERE t0.id = ? LIMIT 1 [1] []

Problem is you can’t quickly take that to your database and run it to see the results. Plugging in the parameters is easy enough, but it takes time. I decided to quickly whip up a script that will take what is in the gist above and convert it to a runnable format. I’ve posted this over at http://code.setfive.com/doctrine-query-log-converter/ . This hopefully will save you some time when you are trying to debug your background processes.

It should work with both Doctrine 1.x/symfony 1.x and Doctrine2.x/Symfony2.x. If you find any issues with it let me know.

Good luck debugging!

AngularJS: onLoad from an iframe directive

A couple of days ago in my journey down the AngularJS rabbit hole I ran into an interesting issue. If you have a directive that’s dynamically adding an iframe tag how can you set an onLoad handler on the iframe with access to the directive’s $scope?

Interestingly, the top StackOverflow answer on Google recommends adding a function to the window object and then setting the onLoad attribute to that function. Although it works, this approach is decidedly not “the Angular way” and would definitely become unwieldy with more than one iframe on the page. I poked around a bit and turns out there’s a better way to do this. The “trick” is that it’s possible to access a directive’s $scope from inside its link function so you can set onLoad on the iframe element from there. This post provides an overview but it’s a bit light on details so here’s a concrete example.

angular.module( 'videoPlayer')

.directive('video', function(){
  return {
    restrict: 'E',
    replace: true,
    templateUrl: 'components/video.tpl.html',    
    link: function(scope, el, attr){
      el.find("iframe")[0].onload = function(){
        scope["onIframeLoaded"]();
      };
    },
    controller: function($scope, $sce){
       
       $scope["onIframeLoaded"] = function(){
         // Do whatever you need to do after the iframe has loaded
       };
       
       $scope["embedUrl"] = $sce.trustAsResourceUrl("https://www.youtube.com/embed/dQw4w9WgXcQ");
    }
  };
})

// components/video.tpl.html
<div class="video-container">
  <iframe ng-src="{{embedUrl}}"></iframe>
</div>

Interns: We interviewed our intern and you won't believe what happened next

This summer we have an engineering intern from Tufts University (go Jumbos) joining the team. He’ll be working on internal projects including Rotorobot and a couple of new ideas. Here’s Phil in his own words.

Could you tell us a little bit about yourself?

Sure. I’m from Haverhill, MA originally so I’d call Boston home. I’m currently attending Tufts University and pursuing a BA in both Computer Science and Cognitive Science. At Tufts, I’m also working with the linguistics department on a couple of research projects surrounding the structure of the mental lexicon.

Where can we find you outside of work and school?

I’ve been playing Rugby at Tufts for the past few years so probably on the pitch, or maybe relaxing in my hammock with a book and an IPA.

What’s been the hardest part about learning PHP and Symfony2?

The hardest parts about learning Symfony2 have been recognizing how the many components of the framework fit together, and allowing the framework to take care of some of the heavy lifting. It was a leap to go from hacking away with straight PHP to designing an application, keeping both structure and modularity in mind.

Which computer science course has helped the most in transitioning to “real world” programming?

The computer science curriculum at Tufts has definitely helped me make the transition into real world programming. In particular, the course: Comp20 - Introduction to Web Development has given me exposure to the many tools that are used in the creation of web applications.

What technology/language/framework/etc. are you excited to learn more about?

This summer I’m excited to learn more about back end programming, the SQL language in particular as well as learning Bash more in depth so I can improve my use of the shell.

So far, what’s your favorite lunch spot been?

My favorite lunch spot so far has definitely been Orinoco in Harvard Square. I will buy some of their hot sauce by the summers end.

And finally, movie quote you live by?

“Crying: Acceptable only at funerals and the Grand Canyon”

For the uninitiated, Orinoco has an authentic Venezuelan hot sauce which has been known to destroy even veteran hot sauce connoisseurs. Here’s Phil deciding to take the plunge: