feat(view): introduce free embedded views
Free embedded views are view instances that are created logically in the same was as views of a ViewContainer, but their dom nodes are not attached. BREAKING CHANGE: - `Renderer.detachFreeHostView` was renamed to `Renderer.detachFreeView` - `DomRenderer.getHostElement()` was generalized into `DomRenderer.getRootNodes()`
This commit is contained in:
@ -23,12 +23,9 @@ import * as renderApi from 'angular2/src/render/api';
|
||||
import {EventDispatcher} from 'angular2/src/render/api';
|
||||
|
||||
export class AppViewContainer {
|
||||
views: List<AppView>;
|
||||
|
||||
constructor() {
|
||||
// The order in this list matches the DOM order.
|
||||
this.views = [];
|
||||
}
|
||||
// The order in this list matches the DOM order.
|
||||
views: List<AppView> = [];
|
||||
freeViews: List<AppView> = [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -115,6 +115,24 @@ export class AppViewManager {
|
||||
this._destroyFreeHostView(parentView, hostView);
|
||||
}
|
||||
|
||||
createFreeEmbeddedView(location: ElementRef, protoViewRef: ProtoViewRef,
|
||||
injector: Injector = null): ViewRef {
|
||||
var protoView = internalProtoView(protoViewRef);
|
||||
var parentView = internalView(location.parentView);
|
||||
var boundElementIndex = location.boundElementIndex;
|
||||
|
||||
var view = this._createPooledView(protoView);
|
||||
this._utils.attachAndHydrateFreeEmbeddedView(parentView, boundElementIndex, view, injector);
|
||||
this._viewHydrateRecurse(view);
|
||||
return new ViewRef(view);
|
||||
}
|
||||
|
||||
destroyFreeEmbeddedView(location: ElementRef, viewRef: ViewRef) {
|
||||
var parentView = internalView(location.parentView);
|
||||
var boundElementIndex = location.boundElementIndex;
|
||||
this._destroyFreeEmbeddedView(parentView, boundElementIndex, internalView(viewRef));
|
||||
}
|
||||
|
||||
createViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
|
||||
protoViewRef: ProtoViewRef, context: ElementRef = null,
|
||||
injector: Injector = null): ViewRef {
|
||||
@ -225,11 +243,18 @@ export class AppViewManager {
|
||||
|
||||
_destroyFreeHostView(parentView, hostView) {
|
||||
this._viewDehydrateRecurse(hostView, true);
|
||||
this._renderer.detachFreeHostView(parentView.render, hostView.render);
|
||||
this._renderer.detachFreeView(hostView.render);
|
||||
this._utils.detachFreeHostView(parentView, hostView);
|
||||
this._destroyPooledView(hostView);
|
||||
}
|
||||
|
||||
_destroyFreeEmbeddedView(parentView, boundElementIndex, view) {
|
||||
this._viewDehydrateRecurse(view, false);
|
||||
this._renderer.detachFreeView(view.render);
|
||||
this._utils.detachFreeEmbeddedView(parentView, boundElementIndex, view);
|
||||
this._destroyPooledView(view);
|
||||
}
|
||||
|
||||
_viewHydrateRecurse(view: viewModule.AppView) {
|
||||
this._renderer.hydrateView(view.render);
|
||||
|
||||
@ -260,6 +285,9 @@ export class AppViewManager {
|
||||
for (var j = vc.views.length - 1; j >= 0; j--) {
|
||||
this._destroyViewInContainer(view, i, j);
|
||||
}
|
||||
for (var j = vc.freeViews.length - 1; j >= 0; j--) {
|
||||
this._destroyFreeEmbeddedView(view, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,6 +110,28 @@ export class AppViewManagerUtils {
|
||||
ListWrapper.remove(parentView.freeHostViews, hostView);
|
||||
}
|
||||
|
||||
attachAndHydrateFreeEmbeddedView(parentView: viewModule.AppView, boundElementIndex: number,
|
||||
view: viewModule.AppView, injector: Injector = null) {
|
||||
parentView.changeDetector.addChild(view.changeDetector);
|
||||
var viewContainer = this._getOrCreateViewContainer(parentView, boundElementIndex);
|
||||
ListWrapper.push(viewContainer.freeViews, view);
|
||||
var elementInjector = parentView.elementInjectors[boundElementIndex];
|
||||
for (var i = view.rootElementInjectors.length - 1; i >= 0; i--) {
|
||||
view.rootElementInjectors[i].link(elementInjector);
|
||||
}
|
||||
this._hydrateView(view, injector, elementInjector, parentView.context, parentView.locals);
|
||||
}
|
||||
|
||||
detachFreeEmbeddedView(parentView: viewModule.AppView, boundElementIndex: number,
|
||||
view: viewModule.AppView) {
|
||||
var viewContainer = parentView.viewContainers[boundElementIndex];
|
||||
view.changeDetector.remove();
|
||||
ListWrapper.remove(viewContainer.freeViews, view);
|
||||
for (var i = 0; i < view.rootElementInjectors.length; ++i) {
|
||||
view.rootElementInjectors[i].unlink();
|
||||
}
|
||||
}
|
||||
|
||||
attachViewInContainer(parentView: viewModule.AppView, boundElementIndex: number,
|
||||
contextView: viewModule.AppView, contextBoundElementIndex: number,
|
||||
atIndex: number, view: viewModule.AppView) {
|
||||
@ -118,11 +140,7 @@ export class AppViewManagerUtils {
|
||||
contextBoundElementIndex = boundElementIndex;
|
||||
}
|
||||
parentView.changeDetector.addChild(view.changeDetector);
|
||||
var viewContainer = parentView.viewContainers[boundElementIndex];
|
||||
if (isBlank(viewContainer)) {
|
||||
viewContainer = new viewModule.AppViewContainer();
|
||||
parentView.viewContainers[boundElementIndex] = viewContainer;
|
||||
}
|
||||
var viewContainer = this._getOrCreateViewContainer(parentView, boundElementIndex);
|
||||
ListWrapper.insert(viewContainer.views, atIndex, view);
|
||||
var sibling;
|
||||
if (atIndex == 0) {
|
||||
@ -208,6 +226,15 @@ export class AppViewManagerUtils {
|
||||
view.changeDetector.hydrate(view.context, view.locals, view);
|
||||
}
|
||||
|
||||
_getOrCreateViewContainer(parentView: viewModule.AppView, boundElementIndex: number) {
|
||||
var viewContainer = parentView.viewContainers[boundElementIndex];
|
||||
if (isBlank(viewContainer)) {
|
||||
viewContainer = new viewModule.AppViewContainer();
|
||||
parentView.viewContainers[boundElementIndex] = viewContainer;
|
||||
}
|
||||
return viewContainer;
|
||||
}
|
||||
|
||||
_setUpEventEmitters(view: viewModule.AppView, elementInjector: eli.ElementInjector,
|
||||
boundElementIndex: number) {
|
||||
var emitters = elementInjector.getEventEmitterAccessors();
|
||||
|
@ -237,9 +237,9 @@ export class Renderer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches a free host view's element from the DOM.
|
||||
* Detaches a free view's element from the DOM.
|
||||
*/
|
||||
detachFreeHostView(parentHostViewRef: RenderViewRef, hostViewRef: RenderViewRef) {}
|
||||
detachFreeView(view: RenderViewRef) {}
|
||||
|
||||
/**
|
||||
* Creates a regular view out of the given ProtoView
|
||||
|
@ -47,9 +47,9 @@ export class DomRenderer extends Renderer {
|
||||
return new DomViewRef(this._createView(hostProtoView, element));
|
||||
}
|
||||
|
||||
detachFreeHostView(parentHostViewRef: RenderViewRef, hostViewRef: RenderViewRef) {
|
||||
var hostView = resolveInternalDomView(hostViewRef);
|
||||
this._removeViewNodes(hostView);
|
||||
detachFreeView(viewRef: RenderViewRef) {
|
||||
var view = resolveInternalDomView(viewRef);
|
||||
this._removeViewNodes(view);
|
||||
}
|
||||
|
||||
createView(protoViewRef: RenderProtoViewRef): RenderViewRef {
|
||||
@ -83,9 +83,8 @@ export class DomRenderer extends Renderer {
|
||||
this._moveViewNodesIntoParent(componentView.shadowRoot, componentView);
|
||||
}
|
||||
|
||||
getHostElement(hostViewRef: RenderViewRef) {
|
||||
var hostView = resolveInternalDomView(hostViewRef);
|
||||
return hostView.boundElements[0];
|
||||
getRootNodes(viewRef: RenderViewRef): List</*node*/ any> {
|
||||
return resolveInternalDomView(viewRef).rootNodes;
|
||||
}
|
||||
|
||||
detachComponentView(hostViewRef: RenderViewRef, boundElementIndex: number,
|
||||
|
Reference in New Issue
Block a user