@@ -2497,41 +2497,34 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
2497
2497
parent . replaceChild ( newNode , firstElementToRemove ) ;
2498
2498
}
2499
2499
2500
- // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
2500
+ // Append all the `elementsToRemove` to a fragment. This will...
2501
+ // - remove them from the DOM
2502
+ // - allow them to still be traversed with .nextSibling
2503
+ // - allow a single fragment.qSA to fetch all elements being removed
2501
2504
var fragment = document . createDocumentFragment ( ) ;
2502
- fragment . appendChild ( firstElementToRemove ) ;
2505
+ for ( i = 0 ; i < removeCount ; i ++ ) {
2506
+ fragment . appendChild ( elementsToRemove [ i ] ) ;
2507
+ }
2503
2508
2504
2509
if ( jqLite . hasData ( firstElementToRemove ) ) {
2505
2510
// Copy over user data (that includes Angular's $scope etc.). Don't copy private
2506
2511
// data here because there's no public interface in jQuery to do that and copying over
2507
2512
// event listeners (which is the main use of private data) wouldn't work anyway.
2508
2513
jqLite ( newNode ) . data ( jqLite ( firstElementToRemove ) . data ( ) ) ;
2509
2514
2510
- // Remove data of the replaced element. We cannot just call .remove()
2511
- // on the element it since that would deallocate scope that is needed
2512
- // for the new node. Instead, remove the data "manually".
2513
- if ( ! jQuery ) {
2514
- delete jqLite . cache [ firstElementToRemove [ jqLite . expando ] ] ;
2515
- } else {
2516
- // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
2517
- // the replaced element. The cleanData version monkey-patched by Angular would cause
2518
- // the scope to be trashed and we do need the very same scope to work with the new
2519
- // element. However, we cannot just cache the non-patched version and use it here as
2520
- // that would break if another library patches the method after Angular does (one
2521
- // example is jQuery UI). Instead, set a flag indicating scope destroying should be
2522
- // skipped this one time.
2523
- skipDestroyOnNextJQueryCleanData = true ;
2524
- jQuery . cleanData ( [ firstElementToRemove ] ) ;
2525
- }
2515
+ // Remove $destroy event listeners from `firstElementToRemove` since it is being
2516
+ // replaced, not destroyed.
2517
+ jqLite ( firstElementToRemove ) . off ( '$destroy' ) ;
2526
2518
}
2527
2519
2528
- for ( var k = 1 , kk = elementsToRemove . length ; k < kk ; k ++ ) {
2529
- var element = elementsToRemove [ k ] ;
2530
- jqLite ( element ) . remove ( ) ; // must do this way to clean up expando
2531
- fragment . appendChild ( element ) ;
2532
- delete elementsToRemove [ k ] ;
2533
- }
2520
+ // Cleanup any data/listeners on the elements and children.
2521
+ // This includes invoking the $destroy event on any elements with listeners.
2522
+ jqLite . cleanData ( fragment . querySelectorAll ( '*' ) ) ;
2534
2523
2524
+ // Update the jqLite collection to only contain the `newNode`
2525
+ for ( i = 1 ; i < removeCount ; i ++ ) {
2526
+ delete elementsToRemove [ i ] ;
2527
+ }
2535
2528
elementsToRemove [ 0 ] = newNode ;
2536
2529
elementsToRemove . length = 1 ;
2537
2530
}
0 commit comments