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