I was working on a project when I came across a problem. I had to call an MVC view containing an AngularJS template via ajax request and render it on the page. At first thought it seemed like a child's play, but unless you do it, you won't know it. So I gave it a go. For the sake of brevity, I'll take a very simple example however you can change the code as per your requirements. Suppose I have to request an html file containing AngularJS directives using Ajax and render it on my page. I'll show how how my looked before and after the changes. My AngularJS controller looked like:

testAppControllers.controller("AjaxRequestController", ['$scope','$http', function($scope, $http){
$http.get("template.html").success(function(data){
  $scope.PageName = "MyPage";
  $scope.Data = data; 
}); 
}]);

Here are the contents of template.html file on server.

Welcome to our page at {{PageName}}

And here is how I used this controller is my index.html file.

<div data-ng-controller="AjaxRequestController">
{{Data}}
</div>

Pretty simple huh. That's why I thought but as soon as I opened my index.html file, this was the output.Error Obviously, not something that I expected. So what went wrong here. Why was {{PageName}} not replaced with 'MyPage'?

Solution

The reason why this thing didn't work was because there is no way angular could guess that the data returned by ajax call is actually a template which needs to be compiled. As a result angular doesn't even bother to do anything on the received data. So to handle this situation, we should manually invoke that compile operation using $compile, shouldn't we?

Changes Explained

Let me brief you with the changes that we need to make to our files to make this thing work. index.html We need to remove the {{Data}} directive and added an Id attribute to our controller div. Because we need to recompile the received data before it's attached to the scope, we'll manually append the received data using append method of jqlite. Removing {{Data}} ensures that we don't see template received without compilation. Our view now looks like:

<div id="ajaxRequestDiv" data-ng-controller="AjaxRequestController">
</div>

Controller In our AjaxRequestController, we need to inject another variable $compile. This helps us to manually compile any html element and link it with a scope. We then refer to our view using it's Id and append the received data. Note that we use angular.element to convert html to jqlite object. After we append the data, we manually call angular to compile our received data using $compile.Our controller now looks like.

testAppControllers.controller("AjaxRequestController", ['$scope','$http', '$compile', function($scope, $http, $compile){
$http.get("template.html").success(function(data){
var elem = angular.element(data);
angular.element(document.getElementById("ajaxRequestDiv")).append(elem);
$scope.PageName = "MyPage"; 
$scope.Data = data; 
$compile(elem)($scope);
}); 
}]);

Now if we run index.html file, we get the following output. Bingo it works.

A Word of Caution

Using $compile directly in your AngularJS controller can be a nail in a coffin of bugs. Use it only when it's absolutely required.