fix(core): remove application from the testability registry when the … · angular/angular@3680ad1

@@ -10,7 +10,7 @@ import {ViewEncapsulation} from '../metadata/view';

1010

import {Renderer2} from '../render/api';

1111

import {RendererStyleFlags2} from '../render/api_flags';

1212

import {addToArray, removeFromArray} from '../util/array_utils';

13-

import {assertDefined, assertDomNode, assertEqual, assertString} from '../util/assert';

13+

import {assertDefined, assertDomNode, assertEqual, assertFunction, assertString} from '../util/assert';

1414

import {assertLContainer, assertLView, assertTNodeForLView} from './assert';

1515

import {attachPatchData} from './context_discovery';

1616

import {icuContainerIterate} from './i18n/i18n_tree_shaking';

@@ -418,7 +418,7 @@ function cleanUpView(tView: TView, lView: LView): void {

418418

lView[FLAGS] |= LViewFlags.Destroyed;

419419420420

executeOnDestroys(tView, lView);

421-

removeListeners(tView, lView);

421+

processCleanups(tView, lView);

422422

// For component views only, the local renderer is destroyed at clean up time.

423423

if (lView[TVIEW].type === TViewType.Component && isProceduralRenderer(lView[RENDERER])) {

424424

ngDevMode && ngDevMode.rendererDestroy++;

@@ -443,38 +443,49 @@ function cleanUpView(tView: TView, lView: LView): void {

443443

}

444444445445

/** Removes listeners and unsubscribes from output subscriptions */

446-

function removeListeners(tView: TView, lView: LView): void {

446+

function processCleanups(tView: TView, lView: LView): void {

447447

const tCleanup = tView.cleanup;

448+

const lCleanup = lView[CLEANUP]!;

449+

// `LCleanup` contains both share information with `TCleanup` as well as instance specific

450+

// information appended at the end. We need to know where the end of the `TCleanup` information

451+

// is, and we track this with `lastLCleanupIndex`.

452+

let lastLCleanupIndex = -1;

448453

if (tCleanup !== null) {

449-

const lCleanup = lView[CLEANUP]!;

450454

for (let i = 0; i < tCleanup.length - 1; i += 2) {

451455

if (typeof tCleanup[i] === 'string') {

452456

// This is a native DOM listener

453457

const idxOrTargetGetter = tCleanup[i + 1];

454458

const target = typeof idxOrTargetGetter === 'function' ?

455459

idxOrTargetGetter(lView) :

456460

unwrapRNode(lView[idxOrTargetGetter]);

457-

const listener = lCleanup[tCleanup[i + 2]];

461+

const listener = lCleanup[lastLCleanupIndex = tCleanup[i + 2]];

458462

const useCaptureOrSubIdx = tCleanup[i + 3];

459463

if (typeof useCaptureOrSubIdx === 'boolean') {

460464

// native DOM listener registered with Renderer3

461465

target.removeEventListener(tCleanup[i], listener, useCaptureOrSubIdx);

462466

} else {

463467

if (useCaptureOrSubIdx >= 0) {

464468

// unregister

465-

lCleanup[useCaptureOrSubIdx]();

469+

lCleanup[lastLCleanupIndex = useCaptureOrSubIdx]();

466470

} else {

467471

// Subscription

468-

lCleanup[-useCaptureOrSubIdx].unsubscribe();

472+

lCleanup[lastLCleanupIndex = -useCaptureOrSubIdx].unsubscribe();

469473

}

470474

}

471475

i += 2;

472476

} else {

473477

// This is a cleanup function that is grouped with the index of its context

474-

const context = lCleanup[tCleanup[i + 1]];

478+

const context = lCleanup[lastLCleanupIndex = tCleanup[i + 1]];

475479

tCleanup[i].call(context);

476480

}

477481

}

482+

if (lCleanup !== null) {

483+

for (let i = lastLCleanupIndex + 1; i < lCleanup.length; i++) {

484+

const instanceCleanupFn = lCleanup[i];

485+

ngDevMode && assertFunction(instanceCleanupFn, 'Expecting instance cleanup function.');

486+

instanceCleanupFn();

487+

}

488+

}

478489

lView[CLEANUP] = null;

479490

}

480491

}