AngularJS + JQuery: 如何让动态内容在 AngularJS 中工作

我正在使用 jQuery 和 AngularJS 开发一个 Ajax 应用程序。

当我使用 jQuery 的 html函数更新 div 的内容(包含 AngularJS 绑定)时,AngularJS 绑定不起作用。

下面是我正在尝试做的代码:

$(document).ready(function() {
$("#refreshButton").click(function() {
$("#dynamicContent").html("<button ng-click='count = count + 1' ng-init='count=0'>Increment</button><span>count: {{count}} </span>")
});
});
</style><script src="http://docs.angularjs.org/angular-1.0.1.min.js"></script><style>.ng-invalid {
border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="">
<div id='dynamicContent'>
<button ng-click="count = count + 1" ng-init="count=0">
Increment
</button>
<span>count: {{count}} </span>
</div>




<button id='refreshButton'>
Refresh
</button>
</div>

我有一个 ID 为 #dynamicContent的 div 中的动态内容,并且我有一个刷新按钮,它可以在单击刷新时更新这个 div 的内容。如果我不刷新内容,递增就会按预期工作,但是在我刷新之后,AngularJS 绑定就会停止工作。

这在 AngularJS 中可能无效,但我最初是用 jQuery 构建应用程序的,后来开始使用 AngularJS,所以我不能把所有东西都迁移到 AngularJS 中。任何帮助得到这个工作在 AngularJS 非常感谢。

102889 次浏览

You need to call $compile on the HTML string before inserting it into the DOM so that angular gets a chance to perform the binding.

In your fiddle, it would look something like this.

$("#dynamicContent").html(
$compile(
"<button ng-click='count = count + 1' ng-init='count=0'>Increment</button><span>count: \{\{count}} </span>"
)(scope)
);

Obviously, $compile must be injected into your controller for this to work.

Read more in the $compile documentation.

Another Solution in Case You Don't Have Control Over Dynamic Content

This works if you didn't load your element through a directive (ie. like in the example in the commented jsfiddles).

Wrap up Your Content

Wrap your content in a div so that you can select it if you are using JQuery. You an also opt to use native javascript to get your element.

<div class="selector">
<grid-filter columnname="LastNameFirstName" gridname="HomeGrid"></grid-filter>
</div>

Use Angular Injector

You can use the following code to get a reference to $compile if you don't have one.

$(".selector").each(function () {
var content = $(this);
angular.element(document).injector().invoke(function($compile) {
var scope = angular.element(content).scope();
$compile(content)(scope);
});
});

Summary

The original post seemed to assume you had a $compile reference handy. It is obviously easy when you have the reference, but I didn't so this was the answer for me.

One Caveat of the previous code

If you are using a asp.net/mvc bundle with minify scenario you will get in trouble when you deploy in release mode. The trouble comes in the form of Uncaught Error: [$injector:unpr] which is caused by the minifier messing with the angular javascript code.

Here is the way to remedy it:

Replace the prevous code snippet with the following overload.

...
angular.element(document).injector().invoke(
[
"$compile", function($compile) {
var scope = angular.element(content).scope();
$compile(content)(scope);
}
]);
...

This caused a lot of grief for me before I pieced it together.

Addition to @jwize's answer

Because angular.element(document).injector() was giving error injector is not defined So, I have created function that you can run after AJAX call or when DOM is changed using jQuery.

  function compileAngularElement( elSelector) {


var elSelector = (typeof elSelector == 'string') ? elSelector : null ;
// The new element to be added
if (elSelector != null ) {
var $div = $( elSelector );


// The parent of the new element
var $target = $("[ng-app]");


angular.element($target).injector().invoke(['$compile', function ($compile) {
var $scope = angular.element($target).scope();
$compile($div)($scope);
// Finally, refresh the watch expressions in the new element
$scope.$apply();
}]);
}


}

use it by passing just new element's selector. like this

compileAngularElement( '.user' ) ;