fix(core): Unload components when individually disposed.
This commit is contained in:
parent
e6bf33efbf
commit
1ff1792642
|
@ -69,10 +69,15 @@ function _componentProviders(appComponentType: Type): Array<Type | Provider | an
|
||||||
provide(APP_COMPONENT, {useValue: appComponentType}),
|
provide(APP_COMPONENT, {useValue: appComponentType}),
|
||||||
provide(APP_COMPONENT_REF_PROMISE,
|
provide(APP_COMPONENT_REF_PROMISE,
|
||||||
{
|
{
|
||||||
useFactory: (dynamicComponentLoader, injector: Injector) => {
|
useFactory: (dynamicComponentLoader: DynamicComponentLoader, appRef: ApplicationRef_,
|
||||||
|
injector: Injector) => {
|
||||||
|
// Save the ComponentRef for disposal later.
|
||||||
|
var ref: ComponentRef;
|
||||||
// TODO(rado): investigate whether to support providers on root component.
|
// TODO(rado): investigate whether to support providers on root component.
|
||||||
return dynamicComponentLoader.loadAsRoot(appComponentType, null, injector)
|
return dynamicComponentLoader.loadAsRoot(appComponentType, null, injector,
|
||||||
|
() => { appRef._unloadComponent(ref); })
|
||||||
.then((componentRef) => {
|
.then((componentRef) => {
|
||||||
|
ref = componentRef;
|
||||||
if (isPresent(componentRef.location.nativeElement)) {
|
if (isPresent(componentRef.location.nativeElement)) {
|
||||||
injector.get(TestabilityRegistry)
|
injector.get(TestabilityRegistry)
|
||||||
.registerApplication(componentRef.location.nativeElement,
|
.registerApplication(componentRef.location.nativeElement,
|
||||||
|
@ -81,7 +86,7 @@ function _componentProviders(appComponentType: Type): Array<Type | Provider | an
|
||||||
return componentRef;
|
return componentRef;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
deps: [DynamicComponentLoader, Injector]
|
deps: [DynamicComponentLoader, ApplicationRef, Injector]
|
||||||
}),
|
}),
|
||||||
provide(appComponentType,
|
provide(appComponentType,
|
||||||
{
|
{
|
||||||
|
@ -394,6 +399,10 @@ export class ApplicationRef_ extends ApplicationRef {
|
||||||
this._changeDetectorRefs.push(changeDetector);
|
this._changeDetectorRefs.push(changeDetector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unregisterChangeDetector(changeDetector: ChangeDetectorRef): void {
|
||||||
|
ListWrapper.remove(this._changeDetectorRefs, changeDetector);
|
||||||
|
}
|
||||||
|
|
||||||
bootstrap(componentType: Type,
|
bootstrap(componentType: Type,
|
||||||
providers?: Array<Type | Provider | any[]>): Promise<ComponentRef> {
|
providers?: Array<Type | Provider | any[]>): Promise<ComponentRef> {
|
||||||
var completer = PromiseWrapper.completer();
|
var completer = PromiseWrapper.completer();
|
||||||
|
@ -408,12 +417,8 @@ export class ApplicationRef_ extends ApplicationRef {
|
||||||
var injector: Injector = this._injector.resolveAndCreateChild(componentProviders);
|
var injector: Injector = this._injector.resolveAndCreateChild(componentProviders);
|
||||||
var compRefToken: Promise<ComponentRef> = injector.get(APP_COMPONENT_REF_PROMISE);
|
var compRefToken: Promise<ComponentRef> = injector.get(APP_COMPONENT_REF_PROMISE);
|
||||||
var tick = (componentRef) => {
|
var tick = (componentRef) => {
|
||||||
var appChangeDetector = internalView(componentRef.hostView).changeDetector;
|
this._loadComponent(componentRef);
|
||||||
this._changeDetectorRefs.push(appChangeDetector.ref);
|
|
||||||
this.tick();
|
|
||||||
completer.resolve(componentRef);
|
completer.resolve(componentRef);
|
||||||
this._rootComponents.push(componentRef);
|
|
||||||
this._bootstrapListeners.forEach((listener) => listener(componentRef));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var tickResult = PromiseWrapper.then(compRefToken, tick);
|
var tickResult = PromiseWrapper.then(compRefToken, tick);
|
||||||
|
@ -429,6 +434,24 @@ export class ApplicationRef_ extends ApplicationRef {
|
||||||
return completer.promise;
|
return completer.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
_loadComponent(ref): void {
|
||||||
|
var appChangeDetector = internalView(ref.hostView).changeDetector;
|
||||||
|
this._changeDetectorRefs.push(appChangeDetector.ref);
|
||||||
|
this.tick();
|
||||||
|
this._rootComponents.push(ref);
|
||||||
|
this._bootstrapListeners.forEach((listener) => listener(ref));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
_unloadComponent(ref): void {
|
||||||
|
if (!ListWrapper.contains(this._rootComponents, ref)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.unregisterChangeDetector(internalView(ref.hostView).changeDetector.ref);
|
||||||
|
ListWrapper.remove(this._rootComponents, ref);
|
||||||
|
}
|
||||||
|
|
||||||
get injector(): Injector { return this._injector; }
|
get injector(): Injector { return this._injector; }
|
||||||
|
|
||||||
get zone(): NgZone { return this._zone; }
|
get zone(): NgZone { return this._zone; }
|
||||||
|
|
|
@ -12,7 +12,8 @@ import {
|
||||||
} from 'angular2/testing_internal';
|
} from 'angular2/testing_internal';
|
||||||
import {IS_DART, isPresent, stringify} from 'angular2/src/facade/lang';
|
import {IS_DART, isPresent, stringify} from 'angular2/src/facade/lang';
|
||||||
import {bootstrap} from 'angular2/bootstrap';
|
import {bootstrap} from 'angular2/bootstrap';
|
||||||
import {ApplicationRef} from 'angular2/src/core/application_ref';
|
import {platform, applicationDomProviders} from 'angular2/src/core/application_common';
|
||||||
|
import {applicationCommonProviders, ApplicationRef} from 'angular2/src/core/application_ref';
|
||||||
import {Component, Directive, View} from 'angular2/core';
|
import {Component, Directive, View} from 'angular2/core';
|
||||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||||
import {DOCUMENT} from 'angular2/render';
|
import {DOCUMENT} from 'angular2/render';
|
||||||
|
@ -21,6 +22,7 @@ import {provide, Inject, Injector} from 'angular2/core';
|
||||||
import {ExceptionHandler} from 'angular2/src/facade/exceptions';
|
import {ExceptionHandler} from 'angular2/src/facade/exceptions';
|
||||||
import {Testability, TestabilityRegistry} from 'angular2/src/core/testability/testability';
|
import {Testability, TestabilityRegistry} from 'angular2/src/core/testability/testability';
|
||||||
import {ComponentRef_} from "angular2/src/core/linker/dynamic_component_loader";
|
import {ComponentRef_} from "angular2/src/core/linker/dynamic_component_loader";
|
||||||
|
import {compilerProviders} from 'angular2/src/compiler/compiler';
|
||||||
|
|
||||||
@Component({selector: 'hello-app'})
|
@Component({selector: 'hello-app'})
|
||||||
@View({template: '{{greeting}} world!'})
|
@View({template: '{{greeting}} world!'})
|
||||||
|
@ -161,6 +163,21 @@ export function main() {
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
it('should unregister change detectors when components are disposed',
|
||||||
|
inject([AsyncTestCompleter], (async) => {
|
||||||
|
var app = platform().application([
|
||||||
|
applicationCommonProviders(),
|
||||||
|
applicationDomProviders(),
|
||||||
|
compilerProviders(),
|
||||||
|
testProviders
|
||||||
|
]);
|
||||||
|
app.bootstrap(HelloRootCmp)
|
||||||
|
.then((ref) => {
|
||||||
|
ref.dispose();
|
||||||
|
expect(() => app.tick()).not.toThrow();
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
it("should make the provided bindings available to the application component",
|
it("should make the provided bindings available to the application component",
|
||||||
inject([AsyncTestCompleter], (async) => {
|
inject([AsyncTestCompleter], (async) => {
|
||||||
|
|
Loading…
Reference in New Issue