2

私にとってバグのように見えるものに気付きましたが、おそらく$compileAngularJS でサービスを誤用している可能性があります。angularjs コードをコンパイルして div に表示する「動的」と呼ばれるディレクティブがあります。その場合にコンパイルするコードには含まれておりng-controllers、それらのコントローラーはイベントをリッスンしています。問題は、コントローラーが置き換えられた後も「死んでいない」ように見えることです。これは、コントローラーを消去する必要がある場合でも、イベント ($routeChangeSuccessまたはその他のイベント) に反応するためです。問題を示す動作中のplunkrを次に示します。私の問題のコード例を見てみましょう:

私が使用しているディレクティブ:

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);
  });
});

firstButton()次にを呼び出すとsecondButton()checkButton()のみを受信するのではなく、alert(2)2 つのアラートを受信します。ボタン 1/2/1/2/1/2/1/2 を押すと、クリックしたボタンと同じ数のアラートが表示されます。

ここで何が間違っていますか?

ありがとう、ヒルニウス

4

1 に答える 1

2

あなたは本当に近いです。最初に、$compile サービスに対するあなたの意図がわからないので、おそらく何をしようとしているのかを説明します。次に、効果的に ng-include を複製するため、この特定のインスタンスに $compile サービスが必要ない理由を説明します。

あなたがおそらくやろうとしていること:

ディレクティブを使用するための鍵 (特に "$compile" 動的コンテンツを試行する場合) は、どのスコープがどこに渡されるかを確実に把握することです。angularjs に組み込まれているディレクティブのほとんどについて、angular は ( scope.$new()を介して) 作成と破棄を自動的に処理します。 ( scope.$destroy()を介して). スコープを明示的に '$destroy'-ing していないため、それらは削除されません. 別の問題は、子スコープを作成せずに現在のスコープに「動的」ディレクティブを直接アタッチすることです.またはディレクティブ内のアイソレート スコープ ($new 経由):

プランクの例

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 );
            });
        }
    };
});

おそらくすべきこと:

このようないくつかの小さなテンプレートの場合は、(以下の plunkr に示されているように put を介して) $templateCache に配置することを検討して、テンプレートに対するすべてのリクエストが自動的にロードできるようにすることを検討する必要があります。また、「html は適切にサニタイズされていますか?」などの他のことも考慮する必要があります。または「コンテンツを適切にアニメーション化しますか?」。これらは ng-include で自動的に処理され、コピーしようとしているように見えます。

プランクの例

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>");
})

あとは、ビルド済みのng-include ディレクティブを次のように使用するだけです。

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

あなたを助けるためのng-includeソース

これが理解を深めるのに役立つことを願っています。

于 2014-03-16T06:43:21.307 に答える