は私にいくつかの時間がかかりましたが、最終的に私は希望の動作
ファーストを達成することができました、代わりに質問に示すように、ダイアログサービスに直接スコープを渡すので、子スコープを作成するために、より良いit'sオプションで渡されたスコープから
このように、$ compileがモーダルを構築するために呼び出されるたびに、モーダルが閉じられたときに新しく作成されたスコープを破壊するのは簡単です。
サービスの結果のコードは次のようになります。この時点で
angular.module("app", [])
.factory("DialogService", function($q, $compile){
return {
toast:function(text){
Dialog.toast(text);
},
alert:function(text){
var deferred = $q.defer();
var d = Dialog.alert(text);
d.bind("hide", function(){
deferred.resolve();
});
return deferred.promise;
},
showModal:function(options){
var childScope;
var dialog = new Dialog(options);
dialog.show(function(){
var self = this;
if ("scope" in options){
var childScope = options.scope.$new();
$compile(self.contentLayer)(childScope);
options.scope.dismiss = function(){
dialog.hide();
}
dialog.bind("hide", function(){
childScope.$destroy();
});
}
});
if ("hide" in options){
dialog.bind("hide", options.hide);
}
},
confirm:function(text){
var deferred = $q.defer();
Dialog.confirm(text, function(){
deferred.resolve();
}, function(){
deferred.reject();
});
return deferred.promise;
}
}
})
;
エクストラ
、私は問題を解決思ったが、コンソールログを私はそれがサイクルを消化見ることができました私は新しいダイアログを開くたびにますます稼働していますが、今回は時計が一定のままです。
私はカスタムディレクティブがたくさんあるということが起こっていました。上記のようなシナリオでは、パフォーマンスの問題を回避するために、すべてのdirective'sリンク機能の末尾に以下の行を追加することについて非常に慎重に - 私:
var watchers = [
$scope.$watch(...),
$scope.$watch(...),
...
];
...
var observer = new MutationObserver(function(mutations) {
if (!document.body.contains($element[0])){
observer.disconnect();
dropdown.remove();
for (var i = 0; i < watchers.length; i++){
watchers[i]();
}
$scope.$destroy();
return;
}
});
var config = { childList: true, subtree: false /*attributes: true, characterData: true*/ };
observer.observe(document.querySelector('body'), config);
は右、正常に見えますか?うーん...ほとんどの時間の作品が、私はディレクティブ内でこのような何かを持っている場合(それはそうだった):
var clickHandler = function(event){
var isChild = $($element).has(event.target).length > 0 || $(dropdown).has(event.target).length > 0;
var isSelf = $element[0] == event.target || dropdown == event.target;
$scope.$apply(function(){
if (!isChild && !isSelf) {
$scope.mdSelectCtrl.dismiss();
}
});
}
$document.bind('click', clickHandler);
それは、コンパイルクリックイベントの原因を、すべての$上のクリックイベントを追加しました別のダイジェストサイクル(たとえスコープが破壊されたとしても、この時点では深く掘り下げたいとは思わなかった)。モーダルコンテンツで同じディレクティブを10〜15回簡単に使うことができるということを考慮すると、$ compileを呼び出すたびに、クリックごとに多くのダイジェストサイクルが実行され、パフォーマンスが低下します。
これに対する解決策は簡単です:ディレクティブのスコープが破棄されると、DOMのイベントリスナーを削除します。
var observer = new MutationObserver(function(mutations) {
if (!document.body.contains($element[0])){
observer.disconnect();
dropdown.remove();
for (var i = 0; i < watchers.length; i++){
watchers[i]();
}
$scope.$destroy();
$document.unbind('click', clickHandler);
return;
}
});
注
ダイアログサービスを変更した後、私は多分MutationObserverであることを実感ノードがまだ存在するかどうかを追跡する必要はなく、代わりに使用できます。
$scope.$on("destroy")
ウナギは今日のためにそれをテストするためのコードを変更するのが好きです。
偽のスコープオブジェクトを作成し、それをオプションに渡すとどうなりますか(ダイアログにスコープにプロパティが必要な場合)または、単にスコープオブジェクトを渡さないとしたら? –
angleは、スコープが破棄されたときにスコープに登録されているウォッチャーを自動的に削除します。各モーダルに対して同じスコープを何度も何度も繰り返し使用していますか、手動でDOM要素を追加したり削除したりしていますか? – TheSharpieOne
ガードコレクタがスコープオブジェクトを破棄するときに、ビルトインディレクティブによって追加されたウォッチャーがスコープとともに角をなして削除されます。 –