如何通过jQuery的.append()方法添加DOM元素(Angular指令)?

53

有没有办法添加一个带有 jQuery 方法(如 append())的 Angular 指令元素,并让 Angular 进行编译和链接,使其像第一次包含该指令一样正常工作?

示例:


app.directive('myAngularDirective', [function () {
    ...
    // Lots of stuff in here; works when used normally but not when added via jQuery
});

$("body").append("<my-angular-directive />");

目前它只是添加了一个名为“my-angular-directive”的空DOM元素,但是Angular没有启动并发挥其魔力。


我的怀疑是你需要告诉 Angular 新元素已经存在了,因为如果你是动态添加的,它可能在文档准备就绪时并不存在。 - hammus
如果可能的话,确实应该尽量避免使用任何jquery,但我不久前也遇到了类似的问题,这是我的问题,正确的答案应该能够帮助你。简短的答案是使用$compile。 - Ty Danielson
6个回答

77

正确的方法是使用:$compile,如果您的指令返回directive definition object(顺便说一下,这是推荐的方法),那么您可以在其上调用link函数(例如为了注入scope)。

$('body').append($compile("<my-angular-directive />")(scope));
scope.$apply(); 

4
你的代码还不完整。能否请你发布一个 jsfiddle 版本的代码? - Monojit Sarkar
如果您已经在 $digest 循环内部,那该怎么办呢?或许可以使用 $timeout 代替。 - Ivan Rubinson

17

下面是从Angular文档中的一个完整示例:

// 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>


对我来说,这似乎是最简单的解决方案。 - dewd
OP正在询问指令。 - Rafael Herscovici

2
理想情况下,您应该避免那样做。
然而,如果您真的非常需要,那么您可以注入并使用$compile服务,然后跟着一个element.append
如果您的指令不需要访问特定的作用域,那么您甚至可以在应用程序模块的run函数中将$compile$rootScope服务分配给window,然后通过创建新的scope($rootScope.new())并使用$rootScope.apply()来包装元素的添加,在angular上下文之外使用它们。

12
为什么应该避免动态添加元素?有替代方案吗? - Marcos Pereira
我猜你会在视图中使用类似ui.router的东西来将视图放入ui-view中。 - Neil

2

接受的答案没有提供完整的示例,这里提供一个:

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>

1

如果可以的话,你真的应该避免使用任何jQuery,但我不久前遇到了类似的问题,这是我的问题和正确答案,应该能帮助你解决问题。简短的答案是使用$compile。


0

试试这个

angular.element($("#appendToDiv")).append($compile("<my-angular-directive />")($scope));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接