How to add DOM Elements (Angular directives) via jQuery's .append()?
JqueryAngularjsJquery Problem Overview
Is there any way to add an element that is an Angular directive with jQuery methods like append()
and have Angular do its compilation/linking to make it work as though you'd included the directive in the first place?
Example:
app.directive('myAngularDirective', [function () {
...
// Lots of stuff in here; works when used normally but not when added via jQuery
});
$("body").append("<my-angular-directive />");
It currently just appends an empty DOM element called "my-angular-directive," but Angular doesn't kick in and do its magic.
Jquery Solutions
Solution 1 - Jquery
The right way to go is to use: $compile and in case your directive returns: directive definition object
(which is btw. the recommended way to go) you can then call link
function on it (to inject scope
, for example).
$('body').append($compile("<my-angular-directive />")(scope));
scope.$apply();
Solution 2 - Jquery
A complete example, from the Angular documentation:
// Angular boilerplate
var app = angular.module("myApp", []);
app.controller("MyCtrl", function($scope) {
$scope.content = {
label: "hello, world!",
};
});
// Wrap the example in a timeout so it doesn't get executed when Angular
// is first started.
setTimeout(function() {
// The new element to be added
var $div = $("<div ng-controller='MyCtrl'>new: {{content.label}}</div>");
// The parent of the new element
var $target = $("[ng-app]");
angular.element($target).injector().invoke(function($compile) {
var $scope = angular.element($target).scope();
$target.append($compile($div)($scope));
// Finally, refresh the watch expressions in the new element
$scope.$apply();
});
}, 100);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">old: {{content.label}}</div>
</div>
Solution 3 - Jquery
Ideally you should avoid doing that.
However, if you really, really, really need to, then you can inject and use the $compile
service followed by an element.append
.
If your directive doesn't need access to a specific scope, then you can even assign the $compile
and $rootScope
service to window
in the run
function of your application's module and then use them from outside the angular context by creating a new scope
($rootScope.new()
) and wrap the appending of element by using $rootScope.apply()
.
Solution 4 - Jquery
The accepted answer didn't provide a complete example, here's one:
https://codepen.io/rhinojosahdz/pen/ZpGLZG
<body ng-app="app" ng-controller="Ctrl1 as ctrl1">
</body>
<script>
angular.module('app',[])
.controller('Ctrl1', ['$scope', '$compile', function($scope, $compile){
var vm = this;
vm.x = 123;
$('body').append($compile("<hola x='ctrl1.x' />")($scope));
}])
.directive('hola', function(){
return {
template: '<div ng-click="vm.alertXFromGivenScope()">click me!</div>'
,scope: {
x : '='
}
,controller: function(){
var vm = this;
vm.alertXFromGivenScope = function(){
alert(vm.x);
};
}
,controllerAs: 'vm'
,bindToController: true
}
})
<script>
Solution 5 - Jquery
You really want to avoid doing any jquery if you can, but I ran into a similar problem not too long ago, here was my question and the correct answer that should be able to help you out. The short answer is using $compile.
Solution 6 - Jquery
Try this
angular.element($("#appendToDiv")).append($compile("<my-angular-directive />")($scope));