AngularJS + JQuery:如何在 angularjs 中获取动态内容

Posted

技术标签:

【中文标题】AngularJS + JQuery:如何在 angularjs 中获取动态内容【英文标题】:AngularJS + JQuery : How to get dynamic content working in angularjs 【发布时间】:2012-07-31 01:45:24 【问题描述】:

我正在开发一个同时使用 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 中工作的帮助。

【问题讨论】:

使用 JQuery 来实现这个功能有什么特别的原因吗?因为这很容易被角度覆盖:jsfiddle.net/pkozlowski_opensource/YCrFD/2> 这只是我真实用例的简化版本,以显示问题。在实际应用程序中,动态内容是由 grails taglib 生成的,它作为 html 传递给 jquery。所以我不能将 grails taglib 中的所有逻辑移植到 angularjs 以使其成为纯 angularjs。 @pkozlowski.opensource,那个链接失效了?你也应该加入outdoors.stackexchange.com :) 【参考方案1】:

在将 HTML 字符串插入 DOM 之前,您需要在 HTML 字符串上调用 $compile,以便 Angular 有机会执行绑定。

在你的小提琴中,它看起来像这样。

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

显然,$compile 必须注入到您的控制器中才能正常工作。

$compile documentation 中了解更多信息。

【讨论】:

感谢 Noah,当我在控制器方法中编译并直接将该控制器方法绑定到按钮的单击事件时,编译正在工作。这是工作example。但是我在我的实际应用程序中,我不得不从不同的 jquery 函数调用控制器方法。所以我抓住了对范围对象的引用并调用了刷新方法来重新编译它不起作用。这里是example。你能帮助这个例子工作吗? @Raja 当您在 Angular 框架之外调用 Angular 方法/表达式时,您应该调用 $scope.$apply() 来执行异常处理、执行监视等的正确范围生命周期。jsfiddle.net/fABdD/14 @ArtemAndreev 完全正确。 @Raja 如果对您的架构有意义,您还可以将对 $scope.$apply() 的调用移至 refresh() 函数本身:jsfiddle.net/nfreitas/8xkeh/1 原始示例中angular-1.0.1.min.js 的链接是404。这里是@ArtemAndreev-s 示例的更新工作版本:jsfiddle.net/pmorch/fABdD/186 和@NoahFreitas 示例:jsfiddle.net/pmorch/8xkeh/43 在控制器中使用 $compile 和操作 DOM 会导致您走上一条无法测试代码的道路。指令应该用于改变 DOM 而不是控制器。【参考方案2】:

在您无法控制动态内容的情况下的另一种解决方案

如果您没有通过指令加载您的元素(即,如注释 jsfiddles 中的示例),则此方法有效。

结束您的内容

将您的内容包装在一个 div 中,以便在使用 JQuery 时可以选择它。您还可以选择使用本机 javascript 来获取您的元素。

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

使用 Angular 注入器

如果您没有 $compile,您可以使用以下代码获取对 $compile 的引用。

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

总结

原来的帖子似乎假设你有一个方便的 $compile 参考。当您有参考资料时,这显然很容易,但我没有,所以这就是我的答案。

之前代码的一个警告

如果您使用带有 minify 场景的 asp.net/mvc 包,在发布模式下部署时会遇到麻烦。问题以 Uncaught Error: [$injector:unpr] 的形式出现,这是由 minifier 与 angular javascript 代码混淆引起的。

以下是补救方法

将之前的代码 sn-p 替换为以下重载。

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

在我把它拼凑起来之前,这让我很伤心。

【讨论】:

感谢上述代码适用于我的范围和有关编译的解释可用。有时你会错过简单的部分:) 编译后我不得不$digest。 绝对救星,我在我的代码中添加了对角度的条件检查,允许它在插入角度应用程序时使用所有角度优势【参考方案3】:

补充@jwize 的回答

因为angular.element(document).injector() 给出了错误injector is not defined 因此,我创建了可以在 AJAX 调用之后或使用 jQuery 更改 DOM 时运行的函数。

  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();
                    ]);
            

        

通过只传递新元素的选择器来使用它。 像这样

compileAngularElement( '.user' ) ; 

【讨论】:

谢谢,这个包救了我的命,这个包使用 UIKit 作为对话框,在 $scope 函数中动态生成 HTML。作为旁注,我必须更改 $target 的选择器以满足我的需要,在我的情况下为 $["data-ng-controller]"),并注释掉 $scope.apply();因为这个函数已经在一个角度回调中被调用了(所以 apply 已经发生了) @zontar 你也可以通过从参数中获取target 动态。

以上是关于AngularJS + JQuery:如何在 angularjs 中获取动态内容的主要内容,如果未能解决你的问题,请参考以下文章

如何在指令AngularJS中包装jQuery(默认)handsontable?

如何将一些 jQuery 函数转换为 angularjs 指令?

使用browserify时如何在AngularJS中包含jQuery?

如何在 AngularJS 中使用 jQuery

如何将我的 jQuery 代码转换为 AngularJS?

如何从 AngularJS 控制器正确调用 jQuery