Compiling Dynamically Created HTML Elements with Angular

Lately I've been challenging myself to use frameworks that might not often be used together in the same project. I came across an interesting problem, sometimes we don’t have control over how and when elements are created dynamically. This became an issue when I wanted to bind HTML form fields rendered by a Rails gem to an Angular controller.

<%= post.label :name %>
<%= post.text_field :name, {
:class => 'postName',
'ng-keydown' => 'updatePosts($event)'
} %>
<%= t.link_to_add "Add", :post %>

The code above is part of the HTML file that adds new text fields with ng-keydown bound to an event whenever the user clicks the “Add” link. The JavaScript that renders the new text fields is part of the “nested-forms” gemfile. My angular app had no idea these new elements existed.

The fix turned out to be a bit of jQuery inside the link for the directive housing the keydown function. Using the Angular $compile call, we can link our scope to dynamically created elements or HTML.

link: function (scope, ele, attrs) {
$(document).on(‘nested:fieldAdded’, function(event){
scope.$apply(function() {
var field = event.field;
compiledField = $compile(field)(scope);
field.replaceWith(compiledField);
});
});
}

This watches for the fields to be created, selects it, $compiles it, and then replaces the created HTML with the compiled HTML. Interestingly this did not work until I wrapped it in the scope.$apply. Another useful call from Angular, scope.$apply checks a function or expression, executes it, and then calls scope.$digest which in turn updates all bindings.

Working with multiple frameworks may not always be optimal, but you sure can learn a lot.

Like what you read? Give Jesse Abramson a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.