Javascript AngularJS编译代码“保留”;“在后面”;

Javascript AngularJS编译代码“保留”;“在后面”;,javascript,angularjs,angularjs-compile,Javascript,Angularjs,Angularjs Compile,我注意到对我来说似乎是一个bug,但可能更多的是我在AngularJS中误用了$compile服务:我有一个名为“dynamic”的指令,它编译AngularJS代码并将其显示为div。在这种情况下,我编译的代码包含ng控制器,这些控制器正在侦听事件。问题在于,显然控制器在更换后并没有“死亡”,因为应该消失的控制器仍然会对事件(如$routeChangeSuccess或任何其他事件)做出反应。 这里有一个工作说明了这个问题。 让我们看看我的问题的示例代码: 我正在使用的指令: app.direc

我注意到对我来说似乎是一个bug,但可能更多的是我在AngularJS中误用了
$compile
服务:我有一个名为“dynamic”的指令,它编译AngularJS代码并将其显示为div。在这种情况下,我编译的代码包含
ng控制器
,这些控制器正在侦听事件。问题在于,显然控制器在更换后并没有“死亡”,因为应该消失的控制器仍然会对事件(如
$routeChangeSuccess
或任何其他事件)做出反应。 这里有一个工作说明了这个问题。 让我们看看我的问题的示例代码:

我正在使用的指令

app.directive('dynamic', function ($compile) {
    return {
        restrict: 'A',
        replace: true,
        link: function (scope, element, attrs) {
            scope.$watch(attrs.dynamic, function(html) {
                element.html(html);
                $compile(element.contents())(scope);
            });
        }
    };
});
主控制器,然后是我包含的控制器:

app.controller('TestCtrl', function($scope) {
  $scope.dynamicContent = "Default content";

  $scope.firstButton = function() {
    $scope.dynamicContent = "<div ng-controller='FirstCtrl'>The div from first button</div>";
  }

  $scope.secondButton = function() {
    $scope.dynamicContent = "<div ng-controller='SecondCtrl'>The div from second button</div>";
  }

  $scope.checkButton = function() {
    $scope.$broadcast('checkEvent');
  }
});

app.controller('FirstCtrl', function($scope) {
  $scope.$on('checkEvent', function() {
    alert(1);
  });

});
app.controller('SecondCtrl', function($scope) {
  $scope.$on('checkEvent', function() {
    alert(2);
  });
});
app.controller('TestCtrl',函数($scope){
$scope.dynamicContent=“默认内容”;
$scope.firstButton=函数(){
$scope.dynamicContent=“从第一个按钮开始的div”;
}
$scope.secondButton=函数(){
$scope.dynamicContent=“第二个按钮的div”;
}
$scope.checkButton=函数(){
$scope.$broadcast('checkEvent');
}
});
app.controller('FirstCtrl',函数($scope){
$scope.$on('checkEvent',function()){
警报(1);
});
});
应用程序控制器('SecondCtrl',函数($scope){
$scope.$on('checkEvent',function()){
警报(2);
});
});
现在,如果我调用
firstButton()
然后调用
secondButton()
然后调用
checkButton()
,而不是只接收
警报(2)
,我会收到两个警报。如果我点击按钮1/2/1/2/1/2/2/1/2,它将显示与我点击的按钮一样多的警报

我做错了什么


谢谢你,希尔纽斯,你的关系真好。首先,我将告诉您可能希望做什么,因为我不知道您对$compile服务的意图。然后,我将解释为什么这个实例不需要$compile服务,因为您可以有效地复制include

您可能希望做什么:

使用指令(特别是在尝试“$compile”动态内容时)的关键是确保您知道在何处传递什么范围。对于angularjs中内置的大多数指令,angular自动处理创建(via)和销毁(via)。由于您没有显式地“$destroy”,因此不会删除这些作用域。另一个问题是,您直接将“dynamic”指令附加到当前作用域,而没有在指令中创建子作用域或隔离作用域(通过$new):

app.directive('dynamic',function($compile){
返回{
限制:“A”,
链接:函数(范围、元素、属性){
var curScope=null,
curEle=null;
函数removeOld(){
if(光标){
光标。$destroy();
游标范围=空;
curEle.remove();
curEle=null;
}
}
作用域.$watch(attrs.dynamic,函数(html){
removeOld();
curScope=scope.$new();//创建子作用域(而不是隔离)
//可能应该在这里进行一些适当的转义,请参见$sce服务
curEle=angular.element(html);
如果(!curEle.length){
curEle=angular.element(“”+html+“”);
}
$compile(curEle)(光标);
元素。附加(刮匙);
});
}
};
});
您可能应该做的是:

对于像这样的一些小模板,您可能应该考虑将它们放入$TimePraceCHIVER(如下面的SUPKR所示的PUT)所以对于模板的任何请求都会自动加载它。你还必须考虑一些其他的事情,比如“HTML是否正确地被消毒了?”或者“我希望我的内容能正确地被动画化吗?”这些东西是用NG自动处理的,包括它几乎像你想复制的一样。

app.run(函数($templateCache){
$templateCache.put(“btn_default.html”,“默认内容”);
$templateCache.put(“btn_one.html”,“第一个按钮的div”);
$templateCache.put(“btn_two.html”,“第二个按钮的div”);
})
现在,您需要做的就是像这样使用预构建的:


第一个按钮
第二个按钮
检查事件


希望这有助于更好地理解。

您的
动态
指令似乎做了
ng include
所做的事情……除了
ng include
(我的假设)可能使用了$scope。$destroy()要清除由加载的动态模板创建的作用域,我不能使用ng include,因为我要显示的是post请求的结果。在更改动态变量之前,我是否应该在正确的作用域中手动使用$scope.$destroy?是的,我会朝这个方向走。诚然,我一直依赖于控制器的角度处理/对我来说是作用域,所以我不知道这种方法会有多成功。也许看看创建/销毁作用域时会有什么帮助。我在发布您的意图后意识到,$templateCache并不真正适用,但它可能会在将来帮助其他人。非常感谢,真的很有帮助。第二部分也有帮助,但是cache被自动清除?(以避免内存泄漏)。此外,您的第一个plunkr与第二个plunkr相同,您可能希望更正此错误,以供以后的读者很高兴听到,链接对我来说是不同的,不确定那里发生了什么。您应该能够使用和使用$templateCache.remove('btn_default.html')例如,也不要忘记在这里标记一个最佳答案,所以:)。我还有一个问题:如果我没有使用控制器,而只是使用指令和{{}在我编译的代码中,它是自动垃圾收集还是手动销毁?我不确定你所说的{{}是什么意思,但是如果
app.directive('dynamic', function ($compile) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
          var curScope = null,
              curEle = null;

          function removeOld(){
            if( curScope ){
              curScope.$destroy();
              curScope = null;
              curEle.remove();
              curEle = null;
            }
          }

            scope.$watch(attrs.dynamic, function(html) {
                removeOld();
                curScope = scope.$new(); //creates child scope (not isolate)
                //probably should do some proper escaping here see $sce service
                curEle = angular.element( html );
                if( !curEle.length ){
                  curEle = angular.element('<span>'+html+'</span>');
                }
                $compile( curEle )(curScope);
                element.append( curEle );
            });
        }
    };
});
app.run(function( $templateCache ){
  $templateCache.put("btn_default.html", "Default content");
  $templateCache.put("btn_one.html", "<div ng-controller='FirstCtrl'>The div from first button</div>");
  $templateCache.put("btn_two.html", "<div ng-controller='SecondCtrl'>The div from second button</div>");
})
<div ng-controller="TestCtrl">
      <div class="btn btn-default" ng-click="firstButton()">First button</div>
      <div class="btn btn-default" ng-click="secondButton()">Second button</div>
      <div class="btn btn-default" ng-click="checkButton()">Check events</div>
      <div ng-include="dynamicContent"></div>
</div>