fix(dynamic_component_loader): implemented dispose for dynamically-loaded components

This commit is contained in:
vsavkin 2015-06-12 14:14:29 -07:00
parent 9613772455
commit 21dcfc89e9
4 changed files with 49 additions and 14 deletions

View File

@ -43,7 +43,7 @@ export class DynamicComponentLoader {
this._viewManager.createDynamicComponentView(location, componentProtoViewRef, binding, this._viewManager.createDynamicComponentView(location, componentProtoViewRef, binding,
injector); injector);
var component = this._viewManager.getComponent(location); var component = this._viewManager.getComponent(location);
var dispose = () => { throw new BaseException("Not implemented"); }; var dispose = () => { this._viewManager.destroyDynamicComponent(location); };
return new ComponentRef(location, component, dispose); return new ComponentRef(location, component, dispose);
}); });
} }

View File

@ -688,22 +688,20 @@ export class ElementInjector extends TreeNode<ElementInjector> {
this._preBuiltObjects = null; this._preBuiltObjects = null;
this._lightDomAppInjector = null; this._lightDomAppInjector = null;
this._shadowDomAppInjector = null; this._shadowDomAppInjector = null;
this._strategy.callOnDestroy(); this._strategy.callOnDestroy();
this.destroyDynamicComponent();
if (isPresent(this._dynamicallyCreatedComponentBinding) &&
this._dynamicallyCreatedComponentBinding.callOnDestroy) {
this._dynamicallyCreatedComponent.onDestroy();
}
this._strategy.clearInstances(); this._strategy.clearInstances();
this._dynamicallyCreatedComponent = null;
this._dynamicallyCreatedComponentBinding = null;
this._constructionCounter = 0; this._constructionCounter = 0;
} }
destroyDynamicComponent(): void {
if (isPresent(this._dynamicallyCreatedComponentBinding) &&
this._dynamicallyCreatedComponentBinding.callOnDestroy) {
this._dynamicallyCreatedComponent.onDestroy();
this._dynamicallyCreatedComponentBinding = null;
this._dynamicallyCreatedComponent = null;
}
}
hydrate(injector: Injector, host: ElementInjector, preBuiltObjects: PreBuiltObjects): void { hydrate(injector: Injector, host: ElementInjector, preBuiltObjects: PreBuiltObjects): void {
var p = this._proto; var p = this._proto;

View File

@ -133,6 +133,14 @@ export class AppViewManager {
this._destroyFreeEmbeddedView(parentView, boundElementIndex, internalView(viewRef)); this._destroyFreeEmbeddedView(parentView, boundElementIndex, internalView(viewRef));
} }
destroyDynamicComponent(location: ElementRef) {
var hostView = internalView(location.parentView);
var ei = hostView.elementInjectors[location.boundElementIndex];
var componentView = hostView.componentChildViews[location.boundElementIndex];
ei.destroyDynamicComponent();
this._destroyComponentView(hostView, location.boundElementIndex, componentView);
}
createViewInContainer(viewContainerLocation: ElementRef, atIndex: number, createViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
protoViewRef: ProtoViewRef, context: ElementRef = null, protoViewRef: ProtoViewRef, context: ElementRef = null,
injector: Injector = null): ViewRef { injector: Injector = null): ViewRef {

View File

@ -17,7 +17,7 @@ import {
import {TestBed, ViewProxy} from 'angular2/src/test_lib/test_bed'; import {TestBed, ViewProxy} from 'angular2/src/test_lib/test_bed';
import {Injector} from 'angular2/di'; import {Injector} from 'angular2/di';
import {Component, View} from 'angular2/annotations'; import {Component, View, onDestroy} from 'angular2/annotations';
import * as viewAnn from 'angular2/src/core/annotations_impl/view'; import * as viewAnn from 'angular2/src/core/annotations_impl/view';
import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader'; import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader';
import {ElementRef} from 'angular2/src/core/compiler/element_ref'; import {ElementRef} from 'angular2/src/core/compiler/element_ref';
@ -68,6 +68,28 @@ export function main() {
}); });
})); }));
it('should allow destroying dynamically-loaded components',
inject([TestBed, AsyncTestCompleter], (tb, async) => {
tb.overrideView(MyComp, new viewAnn.View({
template: '<dynamic-comp #dynamic></dynamic-comp>',
directives: [DynamicComp]
}));
tb.createView(MyComp).then((view) => {
var dynamicComponent = view.rawView.locals.get("dynamic");
dynamicComponent.done.then((ref) => {
view.detectChanges();
expect(view.rootNodes).toHaveText("hello");
ref.dispose();
expect(ref.instance.destroyed).toBe(true);
expect(view.rootNodes).toHaveText("");
async.done();
});
});
}));
it('should allow to destroy and create them via viewcontainer directives', it('should allow to destroy and create them via viewcontainer directives',
ijTestBed((tb: TestBed, async) => { ijTestBed((tb: TestBed, async) => {
tb.overrideView(MyComp, new viewAnn.View({ tb.overrideView(MyComp, new viewAnn.View({
@ -287,16 +309,23 @@ class DynamicComp {
} }
} }
@Component({selector: 'hello-cmp', appInjector: [DynamicallyCreatedComponentService]}) @Component({
selector: 'hello-cmp',
appInjector: [DynamicallyCreatedComponentService],
lifecycle: [onDestroy]
})
@View({template: "{{greeting}}"}) @View({template: "{{greeting}}"})
class DynamicallyCreatedCmp { class DynamicallyCreatedCmp {
greeting: string; greeting: string;
dynamicallyCreatedComponentService: DynamicallyCreatedComponentService; dynamicallyCreatedComponentService: DynamicallyCreatedComponentService;
destroyed: boolean = false;
constructor(a: DynamicallyCreatedComponentService) { constructor(a: DynamicallyCreatedComponentService) {
this.greeting = "hello"; this.greeting = "hello";
this.dynamicallyCreatedComponentService = a; this.dynamicallyCreatedComponentService = a;
} }
onDestroy() { this.destroyed = true; }
} }
@Component({selector: 'dummy'}) @Component({selector: 'dummy'})