I'm trying to solve a major problem I'm experiencing with angularJS in respect to using dynamically-added html that contains ng-controller
.
Lets say that I want to add a div to the DOM that is a ng-controller
, that blurts it's bound data out to the display. I can achieve this successfully as follows:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script>
var demoData = {
'test1': 'one',
'test2': 'two'
};
var myApp = angular.module('myApp', []);
myApp.controller('TestCtrl', function ($scope) {
$scope.demo = demoData;
});
</script>
</head>
<body>
<div ng-controller="TestCtrl">
{{demo}}
</div>
</body>
</html>
which outputs the following, as expected:
{"test1":"one","test2":"two"}
However, now lets say that the div actually has to be loaded dynamically, perhaps when a user presses a button. In this case, I'd replace the tag in the above example with the following:
<body>
<button onclick="addDiv();">Click to add Div!</button>
<script>
function addDiv() {
var newDiv = $('<div ng-controller="TestCtrl">{{demo}}</div>');
$(document.body).append(newDiv);
}
</script>
</body>
which outputs the following when I click the button:
Click to add Div!
{{demo}}
So far, this makes sense; angular has already worked its way through the DOM, done it's thing, and finished. It's not been told about new stuff being added. So, if we look at the AngularJS manual, right at the bottom of this page, we find out how to tell it we've just added some stuff:
Sometimes you want to get access to the injector of a currently running Angular app from outside Angular. Perhaps, you want to inject and compile some markup after the application has been bootstrapped. You can do this using the extra injector() added to JQuery/jqLite elements. See angular.element.
This is fairly rare but could be the case if a third party library is injecting the markup.
In the following example a new block of HTML containing a ng-controller directive is added to the end of the document body by JQuery. We then compile and link it into the current AngularJS scope. var $div = $('{{content.label}}'); $(document.body).append($div);
angular.element(document).injector().invoke(function($compile) { var scope = angular.element($div).scope(); $compile($div)(scope); });
So... with this in mind, we update addDiv()
function in our example as follows:
function addDiv() {
var $newDiv = $('<div ng-controller="TestCtrl">{{demo}}</div>');
$(document.body).append($newDiv);
angular.element(document).injector().invoke(function ($compile) {
var scope = angular.element($newDiv).scope();
$compile($newDiv)(scope);
});
}
And now when we run it, we should be golden right?
Nope.. we still get the following:
Click to add Div!
{{demo}}
Can you point out what I'm doing wrong, as no end of googling and reading the manual is helping, as everything seems to suggest I've got the code right!