2016-03-18 32 views
2

在Angular.JS項目中,我有一個指令與一個複雜的模板,實例化數千次(在網格中)。Angular JS範圍泄漏與element.empty()

由於性能原因,我不得不在多個子模板中拆分模板。根據指令的範圍值組合,我選擇一個子模板。

性能增益是真實的(在非常大的網格上大於100),但在某些情況下(當子模板包含ng-repeat指令時)Angular正在調用在刪除的DOM元素範圍內聲明的函數。

我的問題歸納爲以下最小代碼:

angular.module('myApp', []).directive('myDirective', ['$compile', '$log', function ($compile, $log) { 
    function display(scopeId, x) { 
    $log.log('func called with', x, 'in scope', scopeId); 

    return x; 
    } 

    return { 
    scope: true, 
    link: function (scope, element) { 
     scope.array = [1, 2, 3]; 
     scope.display = display; 

     scope.$watch(function() { 
     return scope.abc; 
     }, function (newValue) { 
     var newContent = angular.element('<div ng-repeat="item in array">{{display($id, item)}}</div>'); 

     element.empty(); 

     element.append($compile(newContent)(scope)) 
     }); 
    } 
    }; 
}]); 

你可以在這裏進行測試:https://jsfiddle.net/yss4yskm/6/

每次元素被替換(當你點擊複選框),通過創建的每個範圍ng-repeat被泄露:作用域繼續登錄到瀏覽器控制檯,Batarang也顯示泄漏的作用域。

不應該element.empty()刪除所有的子範圍?

爲什麼問題只發生在ng-repeat指令中?

我可以通過創建子範圍並在需要時銷燬(https://jsfiddle.net/yss4yskm/9/)來避免泄漏,但我不應該這樣做。

angular.module('myApp', []).directive('myDirective', ['$compile', '$log', function ($compile, $log) { 
    var childScope; 

    function display(scopeId, x) { 
    $log.log('func called with', x, 'in scope', scopeId); 

    return x; 
    } 

    return { 
    scope: true, 
    link: function (scope, element) { 
     scope.array = [1, 2, 3]; 
     scope.display = display; 

     scope.$watch(function() { 
     return scope.abc; 
     }, function (newValue) { 
     element.empty(); 

     if (childScope) { 
      childScope.$destroy(); 
     } 

     element.append(angular.element('<div ng-repeat="item in array">{{display($id, item)}}</div>')); 

     childScope = scope.$new(); 

     $compile(element.contents())(childScope); 
     }); 
    } 
    }; 
}]); 

謝謝。

+0

你應該做'element.remove()'它也會刪除範圍.. –

+0

'element.remove()'不會刪除範圍。範圍需要被明確銷燬。 –

回答

0

迴應自己。

查看角度來源。 element.empty()調用jQuery.empty(),除此之外沒有其他任何東西!

刪除DOM元素時,對角度範圍的引用將被刪除,但範圍仍位於其父級的子範圍的鏈接列表中。

因此需要子範圍。

+0

'empty()'不會刪除一個元素......它會刪除它的內部html – charlietfl

+0

所以擁有'childScope'是唯一的解決方案嗎? –