AngularJS不清除ng-include创建的子范围

时间:2013-09-29 12:41:11

标签: javascript angularjs angularjs-scope

我有以下用例 - 我提供了一个对话服务,我根据上下文放置了不同的内容。在服务方法中,我手动编译dom元素并使用它来显示使用jquery ui的对话框。代码如下:

var _view = jQuery('<div id="config-dialog"><span ng-include="\'' +  $scope.configView + '\'" ng-controller="' + $scope.configController + '"></span></div>');
var _compiled = $compile(_view.contents())($scope);

然后我触发一个范围事件,该事件应由控制器中定义的范围函数处理

$scope.$broadcast('config-open', $scope.config);

然后我打开对话框,用户执行某些操作并关闭对话框。当对话框关闭时,我从DOM中删除“config-dialog”元素。像这样:

$(this).dialog("destroy");
jQuery('#config-dialog').remove();

然而,下次打开对话框并实例化新控制器时,我会看到'config-open'被处理两次,再次打开对话框时会被处理3次。这意味着我动态创建的ng-include附加的范围不会被破坏。我已经使用Batarang进行了调试,发现实际上没有清除ng-include创建的子范围。 AFAIK AngularJS范围与dom元素相关联,当我删除元素时,范围应该是垃圾收集,但这不会发生。 我的问题是 - AngularJS应该在我的案例中清理范围。我做错了什么,是否有更合适的方式来实现我的用例?

3 个答案:

答案 0 :(得分:4)

当您的对话框关闭时,您实际上应该手动销毁范围。

举个例子,假设你的对话框中有一个dom元素有一个ng-click:

<div class="dialog">
    ....
    <a data-ng-click="closeDialog()">Close Me!</a>
    ....
</div>

然后在您的控制器中,您可以像这样连接点击:

function myController($scope, ....){
    ....
    $scope.closeDialog = function(){
        $scope.$destroy();
        //not to sure about the use of the word "this" here, but you should be able to figure out what element it is somehow
        $(this).dialog("destroy");
        jQuery('#config-dialog').remove();
    }
    ....
}

我认为你遇到的问题是你认为通过破坏范围被破坏的元素。这不是真的。你必须手动销毁范围。

答案 1 :(得分:4)

  

控制器仅用于对话框内容。确定并取消按钮   对话框在对话框内容之外处理

我认为您的HTML看起来像这样:

<div class="dialog">
    <div class="dialog-content" ng-controller="yourcontroller">
       ...your content here 
    </div>

    <button id="btnClose">Close</button>  //your button is outside your controller      
</div>

尝试:angular.element(domElement).scope() 像这样(使用带有委托事件的jquery,因为你是动态创建DOM):

$(document).on("click","#btnClose",function(){
    var dialog = $(this).closest(".dialog");
    //call this to destroy the scope.
    angular.element(dialog.find(".dialog-content")[0]).scope().$destroy();
    //or angular.element(dialog[0]).scope().$destroy(); depending on where you attach your scope.
    //Destroy dialog
    dialog.dialog("destroy");
    dialog.remove();
});

答案 2 :(得分:1)

我会做一些我通常不做的事情,并建议你采取不同的方法。你的问题最有可能是由于JQuery和Angular的结合(没有尝试过你的代码,但似乎是最可能的原因)。 Angular会忽略在框架外完成的事情,这是除非你真的需要,否则不混合的原因之一。

在这种特殊情况下,据我所知,在Angular中你无法做任何事情。

如果我这样做,我可能会首先把我的对话框放在ng-switch(它就像你的JQuery那样添加和删除DOM中的东西),然后让我的开放广播和关闭按钮而是触发ng-switch标准。然后你就有了一个像DOM那样在DOM中添加和删除的对话框,这样你就不必担心Angular和Jquery之间的同步了。

阅读this的第二部分!之前我曾经在Angular中使用Jquery,然后我读了这篇文章并停了下来。现在一切都变得顺利了: - )


编辑:一个小例子html。此示例中的“dialog.template”是由调用者设置的DialogController范围内的变量。

<div ng-switch on="dialog_status">
    <div ng-switch-when="open">
        <div class="dialog" ng-controller="DialogController" ng-include="dialog.template">
           Dialog will appear here 
        </div>
    </div>
</div>