fix(angular): router-outlet memory leak

fixes #16285
This commit is contained in:
Manu Mtz.-Almeida
2018-12-19 00:43:45 +01:00
committed by Manu MA
parent d1cecf142b
commit 2c41823676
4 changed files with 15 additions and 13 deletions

View File

@@ -2,7 +2,6 @@ import { Attribute, ChangeDetectorRef, ComponentFactoryResolver, ComponentRef, D
import { ActivatedRoute, ChildrenOutletContexts, OutletContext, PRIMARY_OUTLET, Router } from '@angular/router';
import { Config } from '../../providers';
import { bindLifecycleEvents } from '../../providers/angular-delegate';
import { NavController } from '../../providers/nav-controller';
import { StackController } from './stack-controller';
@@ -168,12 +167,10 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
const injector = new OutletInjector(activatedRoute, childContexts, this.location.injector);
cmpRef = this.activated = this.location.createComponent(factory, this.location.length, injector);
bindLifecycleEvents(cmpRef.instance, cmpRef.location.nativeElement);
// Calling `markForCheck` to make sure we will run the change detection when the
// `RouterOutlet` is inside a `ChangeDetectionStrategy.OnPush` component.
this.changeDetector.markForCheck();
enteringView = this.stackCtrl.createView(this.activated, activatedRoute);
this.changeDetector.markForCheck();
}
this.activatedView = enteringView;

View File

@@ -2,6 +2,7 @@ import { ComponentRef, NgZone } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { RouterDirection } from '@ionic/core';
import { bindLifecycleEvents } from '../../providers/angular-delegate';
import { NavController } from '../../providers/nav-controller';
import { RouteView, computeStackId, destroyView, getUrl, insertView, isTabSwitch, toSegments } from './stack-utils';
@@ -26,13 +27,16 @@ export class StackController {
this.tabsPrefix = tabsPrefix !== undefined ? toSegments(tabsPrefix) : undefined;
}
createView(enteringRef: ComponentRef<any>, activatedRoute: ActivatedRoute): RouteView {
createView(ref: ComponentRef<any>, activatedRoute: ActivatedRoute): RouteView {
const url = getUrl(this.router, activatedRoute);
const element = (ref && ref.location && ref.location.nativeElement) as HTMLElement;
const unlistenEvents = bindLifecycleEvents(ref.instance, element);
return {
id: this.nextId++,
ref: enteringRef,
element: (enteringRef && enteringRef.location && enteringRef.location.nativeElement) as HTMLElement,
stackId: computeStackId(this.tabsPrefix, url),
unlistenEvents,
element,
ref,
url,
};
}

View File

@@ -76,6 +76,7 @@ export function destroyView(view: RouteView | undefined) {
if (view) {
// TODO lifecycle event
view.ref.destroy();
view.unlistenEvents();
}
}
@@ -86,4 +87,5 @@ export interface RouteView {
element: HTMLElement;
ref: ComponentRef<any>;
savedData?: any;
unlistenEvents: () => void;
}

View File

@@ -1,5 +1,5 @@
import { ApplicationRef, ComponentFactoryResolver, Injectable, InjectionToken, Injector, NgZone, ViewContainerRef } from '@angular/core';
import { FrameworkDelegate } from '@ionic/core';
import { FrameworkDelegate, LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE, LIFECYCLE_WILL_UNLOAD } from '@ionic/core';
import { NavParams } from '../directives/navigation/nav-params';
@@ -106,11 +106,10 @@ export function attachView(
}
const LIFECYCLES = [
'ionViewWillEnter',
'ionViewDidEnter',
'ionViewWillLeave',
'ionViewDidLeave',
'ionViewWillUnload'
LIFECYCLE_WILL_ENTER,
LIFECYCLE_DID_ENTER,
LIFECYCLE_WILL_LEAVE,
LIFECYCLE_DID_LEAVE,
];
export function bindLifecycleEvents(instance: any, element: HTMLElement) {