fix(ViewManager): dehydrate views recursively over ViewContainers

Closes #1560
This commit is contained in:
Tobias Bosch 2015-04-27 14:07:41 -07:00
parent 6fcd3709cf
commit a801da6f7c
3 changed files with 59 additions and 27 deletions

View File

@ -70,8 +70,8 @@ export class AppViewManager {
parentRenderViewRef = parentView.render; parentRenderViewRef = parentView.render;
} }
var hostViewRenderRef = hostView.render; var hostViewRenderRef = hostView.render;
this._utils.dehydrateAndDetachInPlaceHostView(parentView, hostView);
this._viewDehydrateRecurse(hostView); this._viewDehydrateRecurse(hostView);
this._utils.detachInPlaceHostView(parentView, hostView);
this._renderer.destroyInPlaceHostView(parentRenderViewRef, hostViewRenderRef); this._renderer.destroyInPlaceHostView(parentRenderViewRef, hostViewRenderRef);
this._destroyView(hostView); this._destroyView(hostView);
} }
@ -95,7 +95,6 @@ export class AppViewManager {
var boundElementIndex:number = viewContainerLocation.boundElementIndex; var boundElementIndex:number = viewContainerLocation.boundElementIndex;
var viewContainer = parentView.viewContainers[boundElementIndex]; var viewContainer = parentView.viewContainers[boundElementIndex];
var view = viewContainer.views[atIndex]; var view = viewContainer.views[atIndex];
this._utils.dehydrateView(view);
this._viewDehydrateRecurse(view); this._viewDehydrateRecurse(view);
this._utils.detachViewInContainer(parentView, boundElementIndex, atIndex); this._utils.detachViewInContainer(parentView, boundElementIndex, atIndex);
this._renderer.destroyViewInContainer(this._getRenderViewContainerRef(parentView, boundElementIndex), atIndex); this._renderer.destroyViewInContainer(this._getRenderViewContainerRef(parentView, boundElementIndex), atIndex);
@ -167,11 +166,11 @@ export class AppViewManager {
} }
_viewDehydrateRecurse(view:viewModule.AppView) { _viewDehydrateRecurse(view:viewModule.AppView) {
this._utils.dehydrateView(view);
var binders = view.proto.elementBinders; var binders = view.proto.elementBinders;
for (var i = 0; i < binders.length; i++) { for (var i = 0; i < binders.length; i++) {
var componentView = view.componentChildViews[i]; var componentView = view.componentChildViews[i];
if (isPresent(componentView)) { if (isPresent(componentView)) {
this._utils.dehydrateView(componentView);
this._viewDehydrateRecurse(componentView); this._viewDehydrateRecurse(componentView);
if (binders[i].hasDynamicComponent()) { if (binders[i].hasDynamicComponent()) {
this._utils.detachComponentView(view, i); this._utils.detachComponentView(view, i);
@ -182,7 +181,7 @@ export class AppViewManager {
if (isPresent(vc)) { if (isPresent(vc)) {
for (var j = vc.views.length - 1; j >= 0; j--) { for (var j = vc.views.length - 1; j >= 0; j--) {
var childView = vc.views[j]; var childView = vc.views[j];
this._utils.dehydrateView(childView); this._viewDehydrateRecurse(childView);
this._utils.detachViewInContainer(view, i, j); this._utils.detachViewInContainer(view, i, j);
this._destroyView(childView); this._destroyView(childView);
} }
@ -193,7 +192,7 @@ export class AppViewManager {
for (var i = 0; i < view.imperativeHostViews.length; i++) { for (var i = 0; i < view.imperativeHostViews.length; i++) {
var hostView = view.imperativeHostViews[i]; var hostView = view.imperativeHostViews[i];
this._viewDehydrateRecurse(hostView); this._viewDehydrateRecurse(hostView);
this._utils.dehydrateAndDetachInPlaceHostView(view, hostView); this._utils.detachInPlaceHostView(view, hostView);
this._destroyView(hostView); this._destroyView(hostView);
} }
view.render = null; view.render = null;

View File

@ -98,10 +98,8 @@ export class AppViewManagerUtils {
this._hydrateView(hostView, injector, hostElementInjector, new Object(), null); this._hydrateView(hostView, injector, hostElementInjector, new Object(), null);
} }
dehydrateAndDetachInPlaceHostView(parentView:viewModule.AppView, detachInPlaceHostView(parentView:viewModule.AppView,
hostView:viewModule.AppView) { hostView:viewModule.AppView) {
this.dehydrateView(hostView);
if (isPresent(parentView)) { if (isPresent(parentView)) {
parentView.changeDetector.removeChild(hostView.changeDetector); parentView.changeDetector.removeChild(hostView.changeDetector);
ListWrapper.remove(parentView.imperativeHostViews, hostView); ListWrapper.remove(parentView.imperativeHostViews, hostView);

View File

@ -232,7 +232,15 @@ export function main() {
}); });
describe('recurse into static child component views', () => { describe('recursively destroy dynamic child component views', () => {
// TODO
});
});
describe('static child components', () => {
describe('recursively create when not cached', () => {
var hostView, componentProtoView, nestedProtoView; var hostView, componentProtoView, nestedProtoView;
beforeEach( () => { beforeEach( () => {
hostView = createView(createProtoView( hostView = createView(createProtoView(
@ -267,19 +275,16 @@ export function main() {
expect(renderer.spy('setEventDispatcher')).toHaveBeenCalledWith(cmpView.render, cmpView); expect(renderer.spy('setEventDispatcher')).toHaveBeenCalledWith(cmpView.render, cmpView);
}); });
}); });
});
describe('createDynamicComponentView', () => { describe('recursively hydrate when getting from from the cache', () => {
// TODO: implement this! // TODO(tbosch): implement this
describe('recurse into static child component views', () => {
// TODO
}); });
describe('recurse into dynamic child component views', () => { describe('recursively dehydrate', () => {
// TODO // TODO(tbosch): implement this
}); });
});
});
describe('createInPlaceHostView', () => { describe('createInPlaceHostView', () => {
@ -347,9 +352,14 @@ export function main() {
hostRenderViewRef = hostView.render; hostRenderViewRef = hostView.render;
}); });
it('should dehydrateAndDetach', () => { it('should dehydrate', () => {
manager.destroyInPlaceHostView(elementRef(parentHostView, 0), hostView); manager.destroyInPlaceHostView(elementRef(parentHostView, 0), hostView);
expect(utils.spy('dehydrateAndDetachInPlaceHostView')).toHaveBeenCalledWith(parentView, hostView); expect(utils.spy('detachInPlaceHostView')).toHaveBeenCalledWith(parentView, hostView);
});
it('should detach', () => {
manager.destroyInPlaceHostView(elementRef(parentHostView, 0), hostView);
expect(utils.spy('dehydrateView')).toHaveBeenCalledWith(hostView);
}); });
it('should destroy and clear the render view', () => { it('should destroy and clear the render view', () => {
@ -364,7 +374,7 @@ export function main() {
}); });
}); });
describe('recurse into imperativeHostViews', () => { describe('recursively destroy inPlaceHostViews', () => {
// TODO // TODO
}); });
@ -372,9 +382,6 @@ export function main() {
describe('createViewInContainer', () => { describe('createViewInContainer', () => {
// Note: We don't add tests for recursion or viewpool here as we assume that
// this is using the same mechanism as the other methods...
describe('basic functionality', () => { describe('basic functionality', () => {
var parentView, childProtoView; var parentView, childProtoView;
beforeEach( () => { beforeEach( () => {
@ -425,8 +432,6 @@ export function main() {
}); });
describe('destroyViewInContainer', () => { describe('destroyViewInContainer', () => {
// Note: We don't add tests for recursion here as we assume that
// this is using the same mechanism as the other methods...
describe('basic functionality', () => { describe('basic functionality', () => {
var parentView, childProtoView, childView; var parentView, childProtoView, childView;
@ -461,8 +466,38 @@ export function main() {
}); });
}); });
describe('recurse into ViewContainers', () => { describe('recursively destroy views in ViewContainers', () => {
// TODO var parentView, childProtoView, childView;
beforeEach( () => {
parentView = createView(createProtoView(
[createEmptyElBinder()]
));
parentView.render = new ViewRef();
childProtoView = createProtoView();
childView = manager.createViewInContainer(elementRef(parentView, 0), 0, childProtoView, null);
});
it('should dehydrate', () => {
manager.destroyInPlaceHostView(null, parentView);
expect(utils.spy('dehydrateView')).toHaveBeenCalledWith(parentView.viewContainers[0].views[0]);
});
it('should detach', () => {
manager.destroyInPlaceHostView(null, parentView);
expect(utils.spy('detachViewInContainer')).toHaveBeenCalledWith(parentView, 0, 0);
});
it('should not destroy but clear the render view', () => {
manager.destroyInPlaceHostView(null, parentView);
expect(renderer.spy('destroyViewInContainer')).not.toHaveBeenCalled();
expect(childView.render).toBe(null);
});
it('should return the view to the pool', () => {
manager.destroyInPlaceHostView(null, parentView);
expect(viewPool.spy('returnView')).toHaveBeenCalledWith(childView);
});
}); });
}); });