refactor(render): remove recursion from renderer
The goal is to make implementing a renderer straight forward. BREAKING_CHANGE: - Renderer interface was redone / simplified. - `DirectDomRenderer` was replaced by `DomRenderer`. - `DirectDomRenderer.setImperativeComponentRootNodes` is replaced by the following 2 steps: 1. `ViewManager.getComponentView(elementRef) -> ViewRef` 2. `DomRenderer.setComponentViewRootNodes(viewRef, rootNodes)` - all `@View` annotations need to have a template, but the template may be empty. Previously views that had a `renderer` property did not have to have a `template`. - `dynamicComponentLoader.loadIntoNewLocation` does no more allow to pass an element, but requires a css selector. Special syntax: `:document` can be used as prefix to search globally on the document instead of in the provided parent view. Part of #1675
This commit is contained in:
54
modules/angular2/src/core/application.js
vendored
54
modules/angular2/src/core/application.js
vendored
@ -33,17 +33,14 @@ import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
||||
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
|
||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||
import {Renderer, RenderCompiler} from 'angular2/src/render/api';
|
||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
||||
import * as rc from 'angular2/src/render/dom/compiler/compiler';
|
||||
import * as rvf from 'angular2/src/render/dom/view/view_factory';
|
||||
import * as rvh from 'angular2/src/render/dom/view/view_hydrator';
|
||||
import {DomRenderer, DOCUMENT_TOKEN} from 'angular2/src/render/dom/dom_renderer';
|
||||
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view';
|
||||
import {DefaultDomCompiler} from 'angular2/src/render/dom/compiler/compiler';
|
||||
import {internalView} from 'angular2/src/core/compiler/view_ref';
|
||||
|
||||
import {
|
||||
appComponentRefToken,
|
||||
appElementToken,
|
||||
appComponentAnnotatedTypeToken,
|
||||
appDocumentToken,
|
||||
appComponentAnnotatedTypeToken
|
||||
} from './application_tokens';
|
||||
|
||||
var _rootInjector: Injector;
|
||||
@ -56,28 +53,25 @@ var _rootBindings = [
|
||||
|
||||
function _injectorBindings(appComponentType): List<Binding> {
|
||||
return [
|
||||
bind(appDocumentToken).toValue(DOM.defaultDoc()),
|
||||
bind(DOCUMENT_TOKEN).toValue(DOM.defaultDoc()),
|
||||
bind(appComponentAnnotatedTypeToken).toFactory((reader) => {
|
||||
// TODO(rado): investigate whether to support bindings on root component.
|
||||
return reader.read(appComponentType);
|
||||
}, [DirectiveMetadataReader]),
|
||||
|
||||
bind(appElementToken).toFactory((appComponentAnnotatedType, appDocument) => {
|
||||
var selector = appComponentAnnotatedType.annotation.selector;
|
||||
var element = DOM.querySelector(appDocument, selector);
|
||||
if (isBlank(element)) {
|
||||
throw new BaseException(`The app selector "${selector}" did not match any elements`);
|
||||
}
|
||||
return element;
|
||||
}, [appComponentAnnotatedTypeToken, appDocumentToken]),
|
||||
bind(appComponentRefToken).toAsyncFactory((dynamicComponentLoader, injector, appElement,
|
||||
bind(appComponentRefToken).toAsyncFactory((dynamicComponentLoader, injector,
|
||||
appComponentAnnotatedType, testability, registry) => {
|
||||
|
||||
// We need to do this here to ensure that we create Testability and
|
||||
// it's ready on the window for users.
|
||||
registry.registerApplication(appElement, testability);
|
||||
return dynamicComponentLoader.loadIntoNewLocation(appComponentAnnotatedType.type, null, appElement, injector);
|
||||
}, [DynamicComponentLoader, Injector, appElementToken, appComponentAnnotatedTypeToken,
|
||||
var selector = appComponentAnnotatedType.annotation.selector;
|
||||
return dynamicComponentLoader.loadIntoNewLocation(appComponentAnnotatedType.type, null, selector, injector).then( (componentRef) => {
|
||||
var domView = resolveInternalDomView(componentRef.hostView.render);
|
||||
// We need to do this here to ensure that we create Testability and
|
||||
// it's ready on the window for users.
|
||||
registry.registerApplication(domView.boundElements[0], testability);
|
||||
|
||||
return componentRef;
|
||||
});
|
||||
}, [DynamicComponentLoader, Injector, appComponentAnnotatedTypeToken,
|
||||
Testability, TestabilityRegistry]),
|
||||
|
||||
bind(appComponentType).toFactory((ref) => ref.instance,
|
||||
@ -89,18 +83,16 @@ function _injectorBindings(appComponentType): List<Binding> {
|
||||
}, [VmTurnZone]),
|
||||
bind(ShadowDomStrategy).toFactory(
|
||||
(styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, doc.head),
|
||||
[StyleUrlResolver, appDocumentToken]),
|
||||
DirectDomRenderer,
|
||||
bind(Renderer).toClass(DirectDomRenderer),
|
||||
bind(RenderCompiler).toClass(rc.DefaultDomCompiler),
|
||||
[StyleUrlResolver, DOCUMENT_TOKEN]),
|
||||
// TODO(tbosch): We need an explicit factory here, as
|
||||
// we are getting errors in dart2js with mirrors...
|
||||
bind(rvf.ViewFactory).toFactory(
|
||||
(capacity, eventManager, shadowDomStrategy) => new rvf.ViewFactory(capacity, eventManager, shadowDomStrategy),
|
||||
[rvf.VIEW_POOL_CAPACITY, EventManager, ShadowDomStrategy]
|
||||
bind(DomRenderer).toFactory(
|
||||
(eventManager, shadowDomStrategy, doc) => new DomRenderer(eventManager, shadowDomStrategy, doc),
|
||||
[EventManager, ShadowDomStrategy, DOCUMENT_TOKEN]
|
||||
),
|
||||
bind(rvf.VIEW_POOL_CAPACITY).toValue(10000),
|
||||
rvh.RenderViewHydrator,
|
||||
DefaultDomCompiler,
|
||||
bind(Renderer).toAlias(DomRenderer),
|
||||
bind(RenderCompiler).toAlias(DefaultDomCompiler),
|
||||
ProtoViewFactory,
|
||||
// TODO(tbosch): We need an explicit factory here, as
|
||||
// we are getting errors in dart2js with mirrors...
|
||||
|
@ -1,6 +1,4 @@
|
||||
import {OpaqueToken} from 'angular2/di';
|
||||
|
||||
export var appComponentRefToken:OpaqueToken = new OpaqueToken('ComponentRef');
|
||||
export var appElementToken:OpaqueToken = new OpaqueToken('AppElement');
|
||||
export var appComponentAnnotatedTypeToken:OpaqueToken = new OpaqueToken('AppComponentAnnotatedType');
|
||||
export var appDocumentToken:OpaqueToken = new OpaqueToken('AppDocument');
|
||||
|
31
modules/angular2/src/core/compiler/compiler.js
vendored
31
modules/angular2/src/core/compiler/compiler.js
vendored
@ -133,21 +133,14 @@ export class Compiler {
|
||||
if (isBlank(template)) {
|
||||
return null;
|
||||
}
|
||||
if (isPresent(template.renderer)) {
|
||||
var directives = [];
|
||||
pvPromise = this._render.createImperativeComponentProtoView(template.renderer).then( (renderPv) => {
|
||||
return this._compileNestedProtoViews(null, componentBinding, renderPv, directives, true);
|
||||
});
|
||||
} else {
|
||||
var directives = ListWrapper.map(
|
||||
this._flattenDirectives(template),
|
||||
(directive) => this._bindDirective(directive)
|
||||
);
|
||||
var renderTemplate = this._buildRenderTemplate(component, template, directives);
|
||||
pvPromise = this._render.compile(renderTemplate).then( (renderPv) => {
|
||||
return this._compileNestedProtoViews(null, componentBinding, renderPv, directives, true);
|
||||
});
|
||||
}
|
||||
var directives = ListWrapper.map(
|
||||
this._flattenDirectives(template),
|
||||
(directive) => this._bindDirective(directive)
|
||||
);
|
||||
var renderTemplate = this._buildRenderTemplate(component, template, directives);
|
||||
pvPromise = this._render.compile(renderTemplate).then( (renderPv) => {
|
||||
return this._compileNestedProtoViews(null, componentBinding, renderPv, directives, true);
|
||||
});
|
||||
|
||||
MapWrapper.set(this._compiling, component, pvPromise);
|
||||
return pvPromise;
|
||||
@ -187,14 +180,6 @@ export class Compiler {
|
||||
});
|
||||
|
||||
var protoViewDone = (_) => {
|
||||
var childComponentRenderPvRefs = [];
|
||||
ListWrapper.forEach(protoView.elementBinders, (eb) => {
|
||||
if (isPresent(eb.componentDirective)) {
|
||||
var componentPv = eb.nestedProtoView;
|
||||
ListWrapper.push(childComponentRenderPvRefs, isPresent(componentPv) ? componentPv.render : null);
|
||||
}
|
||||
});
|
||||
this._render.mergeChildComponentProtoViews(protoView.render, childComponentRenderPvRefs);
|
||||
return protoView;
|
||||
};
|
||||
if (nestedPVPromises.length > 0) {
|
||||
|
@ -62,14 +62,14 @@ export class DynamicComponentLoader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a component in the element specified by elementOrSelector. The loaded component receives
|
||||
* Loads a component in the element specified by elementSelector. The loaded component receives
|
||||
* injection normally as a hosted view.
|
||||
*/
|
||||
loadIntoNewLocation(typeOrBinding, parentComponentLocation:ElementRef, elementOrSelector:any,
|
||||
loadIntoNewLocation(typeOrBinding, parentComponentLocation:ElementRef, elementSelector:string,
|
||||
injector:Injector = null):Promise<ComponentRef> {
|
||||
return this._compiler.compileInHost(this._getBinding(typeOrBinding)).then(hostProtoViewRef => {
|
||||
var hostViewRef = this._viewManager.createInPlaceHostView(
|
||||
parentComponentLocation, elementOrSelector, hostProtoViewRef, injector);
|
||||
parentComponentLocation, elementSelector, hostProtoViewRef, injector);
|
||||
var newLocation = new ElementRef(hostViewRef, 0);
|
||||
var component = this._viewManager.getComponent(newLocation);
|
||||
|
||||
|
@ -894,7 +894,7 @@ export class ElementInjector extends TreeNode {
|
||||
|
||||
_getPreBuiltObjectByKeyId(keyId:int) {
|
||||
var staticKeys = StaticKeys.instance();
|
||||
if (keyId === staticKeys.viewManagerId) return this._preBuiltObjects.viewManagerId;
|
||||
if (keyId === staticKeys.viewManagerId) return this._preBuiltObjects.viewManager;
|
||||
|
||||
//TODO add other objects as needed
|
||||
return _undefined;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {normalizeBlank} from 'angular2/src/facade/lang';
|
||||
import {ViewRef} from './view_ref';
|
||||
import {DirectDomViewRef} from 'angular2/src/render/dom/direct_dom_renderer';
|
||||
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view';
|
||||
|
||||
/**
|
||||
* @exportedAs angular2/view
|
||||
@ -23,8 +23,7 @@ export class ElementRef {
|
||||
// We need a more general way to read/write to the DOM element
|
||||
// via a proper abstraction in the render layer
|
||||
get domElement() {
|
||||
var renderViewRef:DirectDomViewRef = this.parentView.render;
|
||||
return renderViewRef.delegate.boundElements[this.boundElementIndex];
|
||||
return resolveInternalDomView(this.parentView.render).boundElements[this.boundElementIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
|
4
modules/angular2/src/core/compiler/view.js
vendored
4
modules/angular2/src/core/compiler/view.js
vendored
@ -32,7 +32,7 @@ export class AppView {
|
||||
componentChildViews: List<AppView>;
|
||||
/// Host views that were added by an imperative view.
|
||||
/// This is a dynamically growing / shrinking array.
|
||||
imperativeHostViews: List<AppView>;
|
||||
inPlaceHostViews: List<AppView>;
|
||||
viewContainers: List<AppViewContainer>;
|
||||
preBuiltObjects: List<PreBuiltObjects>;
|
||||
proto: AppProtoView;
|
||||
@ -64,7 +64,7 @@ export class AppView {
|
||||
this.context = null;
|
||||
this.locals = new Locals(null, MapWrapper.clone(protoLocals)); //TODO optimize this
|
||||
this.renderer = renderer;
|
||||
this.imperativeHostViews = [];
|
||||
this.inPlaceHostViews = [];
|
||||
}
|
||||
|
||||
init(changeDetector:ChangeDetector, elementInjectors:List, rootElementInjectors:List,
|
||||
|
157
modules/angular2/src/core/compiler/view_manager.js
vendored
157
modules/angular2/src/core/compiler/view_manager.js
vendored
@ -1,12 +1,11 @@
|
||||
import {Injector, Binding} from 'angular2/di';
|
||||
import {Injectable} from 'angular2/src/di/annotations_impl';
|
||||
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
||||
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||
import * as viewModule from './view';
|
||||
import {ElementRef} from './element_ref';
|
||||
import {ProtoViewRef, ViewRef, internalView, internalProtoView} from './view_ref';
|
||||
import {ViewContainerRef} from './view_container_ref';
|
||||
import {Renderer, RenderViewRef, RenderViewContainerRef} from 'angular2/src/render/api';
|
||||
import {Renderer, RenderViewRef} from 'angular2/src/render/api';
|
||||
import {AppViewManagerUtils} from './view_manager_utils';
|
||||
import {AppViewPool} from './view_pool';
|
||||
|
||||
@ -27,6 +26,12 @@ export class AppViewManager {
|
||||
this._utils = utils;
|
||||
}
|
||||
|
||||
getComponentView(hostLocation:ElementRef):ViewRef {
|
||||
var hostView = internalView(hostLocation.parentView);
|
||||
var boundElementIndex = hostLocation.boundElementIndex;
|
||||
return new ViewRef(hostView.componentChildViews[boundElementIndex]);
|
||||
}
|
||||
|
||||
getViewContainer(location:ElementRef):ViewContainerRef {
|
||||
var hostView = internalView(location.parentView);
|
||||
return hostView.elementInjectors[location.boundElementIndex].getViewContainerRef();
|
||||
@ -47,20 +52,18 @@ export class AppViewManager {
|
||||
if (!binder.hasDynamicComponent()) {
|
||||
throw new BaseException(`There is no dynamic component directive at element ${boundElementIndex}`)
|
||||
}
|
||||
|
||||
var componentView = this._createViewRecurse(componentProtoView);
|
||||
var renderViewRefs = this._renderer.createDynamicComponentView(hostView.render, boundElementIndex, componentProtoView.render);
|
||||
componentView.render = renderViewRefs[0];
|
||||
var componentView = this._createPooledView(componentProtoView);
|
||||
this._renderer.attachComponentView(hostView.render, boundElementIndex, componentView.render);
|
||||
this._utils.attachComponentView(hostView, boundElementIndex, componentView);
|
||||
this._utils.hydrateDynamicComponentInElementInjector(hostView, boundElementIndex, componentBinding, injector);
|
||||
this._utils.hydrateComponentView(hostView, boundElementIndex);
|
||||
this._viewHydrateRecurse(componentView, renderViewRefs, 1);
|
||||
this._viewHydrateRecurse(componentView);
|
||||
|
||||
return new ViewRef(componentView);
|
||||
}
|
||||
|
||||
createInPlaceHostView(parentComponentLocation:ElementRef,
|
||||
hostElementSelector, hostProtoViewRef:ProtoViewRef, injector:Injector):ViewRef {
|
||||
hostElementSelector:string, hostProtoViewRef:ProtoViewRef, injector:Injector):ViewRef {
|
||||
var hostProtoView = internalProtoView(hostProtoViewRef);
|
||||
var parentComponentHostView = null;
|
||||
var parentComponentBoundElementIndex = null;
|
||||
@ -70,27 +73,22 @@ export class AppViewManager {
|
||||
parentComponentBoundElementIndex = parentComponentLocation.boundElementIndex;
|
||||
parentRenderViewRef = parentComponentHostView.componentChildViews[parentComponentBoundElementIndex].render;
|
||||
}
|
||||
var hostView = this._createViewRecurse(hostProtoView);
|
||||
var renderViewRefs = this._renderer.createInPlaceHostView(parentRenderViewRef, hostElementSelector, hostProtoView.render);
|
||||
hostView.render = renderViewRefs[0];
|
||||
var hostRenderView = this._renderer.createInPlaceHostView(parentRenderViewRef, hostElementSelector, hostProtoView.render);
|
||||
var hostView = this._utils.createView(hostProtoView, hostRenderView, this, this._renderer);
|
||||
this._renderer.setEventDispatcher(hostView.render, hostView);
|
||||
this._createViewRecurse(hostView)
|
||||
this._utils.attachAndHydrateInPlaceHostView(parentComponentHostView, parentComponentBoundElementIndex, hostView, injector);
|
||||
this._viewHydrateRecurse(hostView, renderViewRefs, 1);
|
||||
this._viewHydrateRecurse(hostView);
|
||||
return new ViewRef(hostView);
|
||||
}
|
||||
|
||||
destroyInPlaceHostView(parentComponentLocation:ElementRef, hostViewRef:ViewRef) {
|
||||
var hostView = internalView(hostViewRef);
|
||||
var parentView = null;
|
||||
var parentRenderViewRef = null;
|
||||
if (isPresent(parentComponentLocation)) {
|
||||
parentView = internalView(parentComponentLocation.parentView).componentChildViews[parentComponentLocation.boundElementIndex];
|
||||
parentRenderViewRef = parentView.render;
|
||||
}
|
||||
var hostViewRenderRef = hostView.render;
|
||||
this._viewDehydrateRecurse(hostView);
|
||||
this._utils.detachInPlaceHostView(parentView, hostView);
|
||||
this._renderer.destroyInPlaceHostView(parentRenderViewRef, hostViewRenderRef);
|
||||
this._destroyView(hostView);
|
||||
this._destroyInPlaceHostView(parentView, hostView);
|
||||
}
|
||||
|
||||
createViewInContainer(viewContainerLocation:ElementRef,
|
||||
@ -99,25 +97,19 @@ export class AppViewManager {
|
||||
var parentView = internalView(viewContainerLocation.parentView);
|
||||
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
||||
|
||||
var view = this._createViewRecurse(protoView);
|
||||
var renderViewRefs = this._renderer.createViewInContainer(this._getRenderViewContainerRef(parentView, boundElementIndex), atIndex, view.proto.render);
|
||||
view.render = renderViewRefs[0];
|
||||
var view = this._createPooledView(protoView);
|
||||
|
||||
this._renderer.attachViewInContainer(parentView.render, boundElementIndex, atIndex, view.render);
|
||||
this._utils.attachViewInContainer(parentView, boundElementIndex, atIndex, view);
|
||||
this._utils.hydrateViewInContainer(parentView, boundElementIndex, atIndex, injector);
|
||||
this._viewHydrateRecurse(view, renderViewRefs, 1);
|
||||
this._viewHydrateRecurse(view);
|
||||
return new ViewRef(view);
|
||||
}
|
||||
|
||||
destroyViewInContainer(viewContainerLocation:ElementRef, atIndex:number) {
|
||||
var parentView = internalView(viewContainerLocation.parentView);
|
||||
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
||||
var viewContainer = parentView.viewContainers[boundElementIndex];
|
||||
var view = viewContainer.views[atIndex];
|
||||
this._viewDehydrateRecurse(view);
|
||||
this._utils.detachViewInContainer(parentView, boundElementIndex, atIndex);
|
||||
this._renderer.destroyViewInContainer(this._getRenderViewContainerRef(parentView, boundElementIndex), atIndex);
|
||||
this._destroyView(view);
|
||||
this._destroyViewInContainer(parentView, boundElementIndex, atIndex);
|
||||
}
|
||||
|
||||
attachViewInContainer(viewContainerLocation:ElementRef, atIndex:number, viewRef:ViewRef):ViewRef {
|
||||
@ -125,7 +117,7 @@ export class AppViewManager {
|
||||
var parentView = internalView(viewContainerLocation.parentView);
|
||||
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
||||
this._utils.attachViewInContainer(parentView, boundElementIndex, atIndex, view);
|
||||
this._renderer.insertViewIntoContainer(this._getRenderViewContainerRef(parentView, boundElementIndex), atIndex, view.render);
|
||||
this._renderer.attachViewInContainer(parentView.render, boundElementIndex, atIndex, view.render);
|
||||
return viewRef;
|
||||
}
|
||||
|
||||
@ -135,86 +127,105 @@ export class AppViewManager {
|
||||
var viewContainer = parentView.viewContainers[boundElementIndex];
|
||||
var view = viewContainer.views[atIndex];
|
||||
this._utils.detachViewInContainer(parentView, boundElementIndex, atIndex);
|
||||
this._renderer.detachViewFromContainer(this._getRenderViewContainerRef(parentView, boundElementIndex), atIndex);
|
||||
this._renderer.detachViewInContainer(parentView.render, boundElementIndex, atIndex, view.render);
|
||||
return new ViewRef(view);
|
||||
}
|
||||
|
||||
_getRenderViewContainerRef(parentView:viewModule.AppView, boundElementIndex:number) {
|
||||
return new RenderViewContainerRef(parentView.render, boundElementIndex);
|
||||
}
|
||||
|
||||
_createViewRecurse(protoView:viewModule.AppProtoView) {
|
||||
_createPooledView(protoView:viewModule.AppProtoView):viewModule.AppView {
|
||||
var view = this._viewPool.getView(protoView);
|
||||
if (isBlank(view)) {
|
||||
view = this._utils.createView(protoView, this, this._renderer);
|
||||
var binders = protoView.elementBinders;
|
||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
||||
var binder = binders[binderIdx];
|
||||
if (binder.hasStaticComponent()) {
|
||||
var childView = this._createViewRecurse(binder.nestedProtoView);
|
||||
this._utils.attachComponentView(view, binderIdx, childView);
|
||||
}
|
||||
}
|
||||
view = this._utils.createView(protoView, this._renderer.createView(protoView.render), this, this._renderer);
|
||||
this._renderer.setEventDispatcher(view.render, view);
|
||||
this._createViewRecurse(view);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
_destroyView(view:viewModule.AppView) {
|
||||
_createViewRecurse(view:viewModule.AppView) {
|
||||
var binders = view.proto.elementBinders;
|
||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
||||
var binder = binders[binderIdx];
|
||||
if (binder.hasStaticComponent()) {
|
||||
var childView = this._createPooledView(binder.nestedProtoView);
|
||||
this._renderer.attachComponentView(view.render, binderIdx, childView.render);
|
||||
this._utils.attachComponentView(view, binderIdx, childView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_destroyPooledView(view:viewModule.AppView) {
|
||||
// TODO: if the pool is full, call renderer.destroyView as well!
|
||||
this._viewPool.returnView(view);
|
||||
}
|
||||
|
||||
_destroyViewInContainer(parentView, boundElementIndex, atIndex:number) {
|
||||
var viewContainer = parentView.viewContainers[boundElementIndex];
|
||||
var view = viewContainer.views[atIndex];
|
||||
this._viewDehydrateRecurse(view, false);
|
||||
this._utils.detachViewInContainer(parentView, boundElementIndex, atIndex);
|
||||
this._renderer.detachViewInContainer(parentView.render, boundElementIndex, atIndex, view.render);
|
||||
this._destroyPooledView(view);
|
||||
}
|
||||
|
||||
_destroyComponentView(hostView, boundElementIndex, componentView) {
|
||||
this._viewDehydrateRecurse(componentView, false);
|
||||
this._renderer.detachComponentView(hostView.render, boundElementIndex, componentView.render);
|
||||
this._utils.detachComponentView(hostView, boundElementIndex);
|
||||
this._destroyPooledView(componentView);
|
||||
}
|
||||
|
||||
_destroyInPlaceHostView(parentView, hostView) {
|
||||
var parentRenderViewRef = null;
|
||||
if (isPresent(parentView)) {
|
||||
parentRenderViewRef = parentView.render;
|
||||
}
|
||||
this._viewDehydrateRecurse(hostView, true);
|
||||
this._utils.detachInPlaceHostView(parentView, hostView);
|
||||
this._renderer.destroyInPlaceHostView(parentRenderViewRef, hostView.render);
|
||||
// Note: Don't put the inplace host view into the view pool
|
||||
// as it is depending on the element for which it was created.
|
||||
}
|
||||
|
||||
_viewHydrateRecurse(
|
||||
view:viewModule.AppView,
|
||||
renderComponentViewRefs:List<RenderViewRef>,
|
||||
renderComponentIndex:number):number {
|
||||
this._renderer.setEventDispatcher(view.render, view);
|
||||
view:viewModule.AppView) {
|
||||
this._renderer.hydrateView(view.render);
|
||||
|
||||
var binders = view.proto.elementBinders;
|
||||
for (var i = 0; i < binders.length; ++i) {
|
||||
if (binders[i].hasStaticComponent()) {
|
||||
var childView = view.componentChildViews[i];
|
||||
childView.render = renderComponentViewRefs[renderComponentIndex++];
|
||||
this._utils.hydrateComponentView(view, i);
|
||||
renderComponentIndex = this._viewHydrateRecurse(
|
||||
view.componentChildViews[i],
|
||||
renderComponentViewRefs,
|
||||
renderComponentIndex
|
||||
this._viewHydrateRecurse(
|
||||
view.componentChildViews[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
return renderComponentIndex;
|
||||
}
|
||||
|
||||
_viewDehydrateRecurse(view:viewModule.AppView) {
|
||||
_viewDehydrateRecurse(view:viewModule.AppView, forceDestroyComponents) {
|
||||
this._utils.dehydrateView(view);
|
||||
this._renderer.dehydrateView(view.render);
|
||||
var binders = view.proto.elementBinders;
|
||||
for (var i = 0; i < binders.length; i++) {
|
||||
var componentView = view.componentChildViews[i];
|
||||
if (isPresent(componentView)) {
|
||||
this._viewDehydrateRecurse(componentView);
|
||||
if (binders[i].hasDynamicComponent()) {
|
||||
this._utils.detachComponentView(view, i);
|
||||
this._destroyView(componentView);
|
||||
if (binders[i].hasDynamicComponent() || forceDestroyComponents) {
|
||||
this._destroyComponentView(view, i, componentView);
|
||||
} else {
|
||||
this._viewDehydrateRecurse(componentView, false);
|
||||
}
|
||||
}
|
||||
var vc = view.viewContainers[i];
|
||||
if (isPresent(vc)) {
|
||||
for (var j = vc.views.length - 1; j >= 0; j--) {
|
||||
var childView = vc.views[j];
|
||||
this._viewDehydrateRecurse(childView);
|
||||
this._utils.detachViewInContainer(view, i, j);
|
||||
this._destroyView(childView);
|
||||
this._destroyViewInContainer(view, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// imperativeHostViews
|
||||
for (var i = 0; i < view.imperativeHostViews.length; i++) {
|
||||
var hostView = view.imperativeHostViews[i];
|
||||
this._viewDehydrateRecurse(hostView);
|
||||
this._utils.detachInPlaceHostView(view, hostView);
|
||||
this._destroyView(hostView);
|
||||
// inPlaceHostViews
|
||||
for (var i = view.inPlaceHostViews.length-1; i>=0; i--) {
|
||||
var hostView = view.inPlaceHostViews[i];
|
||||
this._destroyInPlaceHostView(view, hostView);
|
||||
}
|
||||
view.render = null;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import * as avmModule from './view_manager';
|
||||
import {Renderer} from 'angular2/src/render/api';
|
||||
import {BindingPropagationConfig, Locals} from 'angular2/change_detection';
|
||||
import {DirectiveMetadataReader} from './directive_metadata_reader';
|
||||
import {RenderViewRef} from 'angular2/src/render/api';
|
||||
|
||||
@Injectable()
|
||||
export class AppViewManagerUtils {
|
||||
@ -27,8 +28,11 @@ export class AppViewManagerUtils {
|
||||
}
|
||||
}
|
||||
|
||||
createView(protoView:viewModule.AppProtoView, viewManager:avmModule.AppViewManager, renderer:Renderer): viewModule.AppView {
|
||||
createView(protoView:viewModule.AppProtoView, renderView:RenderViewRef, viewManager:avmModule.AppViewManager, renderer:Renderer): viewModule.AppView {
|
||||
var view = new viewModule.AppView(renderer, protoView, protoView.protoLocals);
|
||||
// TODO(tbosch): pass RenderViewRef as argument to AppView!
|
||||
view.render = renderView;
|
||||
|
||||
var changeDetector = protoView.protoChangeDetector.instantiate(view);
|
||||
|
||||
var binders = protoView.elementBinders;
|
||||
@ -96,7 +100,7 @@ export class AppViewManagerUtils {
|
||||
hostElementInjector = parentComponentHostView.elementInjectors[parentComponentBoundElementIndex];
|
||||
var parentView = parentComponentHostView.componentChildViews[parentComponentBoundElementIndex];
|
||||
parentView.changeDetector.addChild(hostView.changeDetector);
|
||||
ListWrapper.push(parentView.imperativeHostViews, hostView);
|
||||
ListWrapper.push(parentView.inPlaceHostViews, hostView);
|
||||
}
|
||||
this._hydrateView(hostView, injector, hostElementInjector, new Object(), null);
|
||||
}
|
||||
@ -105,7 +109,7 @@ export class AppViewManagerUtils {
|
||||
hostView:viewModule.AppView) {
|
||||
if (isPresent(parentView)) {
|
||||
parentView.changeDetector.removeChild(hostView.changeDetector);
|
||||
ListWrapper.remove(parentView.imperativeHostViews, hostView);
|
||||
ListWrapper.remove(parentView.inPlaceHostViews, hostView);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user