refactor(core): introduce ViewRef and ProtoViewRef

BREAKING CHANGES:
- `NgElement` merged into `ElementRef`
- `Compiler.compile…` returns `ProtoViewRef`
- `ViewContainer` uses `ProtoViewRef`s and `ViewRef`s.
- `ViewRef`/`ProtoViewRef` in renderer were renamed to
  `RenderViewRef`/`RenderProtoViewRef`.

Related to #1477
Closes #1592
This commit is contained in:
Tobias Bosch
2015-04-28 11:20:01 -07:00
parent 1205f54d01
commit 09f8d8f7ba
35 changed files with 473 additions and 404 deletions

View File

@ -54,7 +54,7 @@ import {DEFAULT} from 'angular2/change_detection';
* - `@Descendants query:Query<DirectiveType>`: A live collection of any child directives (will be implemented in later relaese).
*
* To inject element-specific special objects, declare the constructor parameter as:
* - `element: NgElement` to obtain a DOM element (DEPRECATED: replacement coming)
* - `element: ElementRef` to obtain a reference to logical element in the view.
* - `viewContainer: ViewContainerRef` to control child template instantiation, for {@link Viewport} directives only
* - `bindingPropagation: BindingPropagation` to control change detection in a more granular way.
*

View File

@ -37,10 +37,10 @@ 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 {internalView} from 'angular2/src/core/compiler/view_ref';
import {
appComponentRefToken,
appChangeDetectorToken,
appElementToken,
appComponentAnnotatedTypeToken,
appDocumentToken,
@ -80,8 +80,6 @@ function _injectorBindings(appComponentType): List<Binding> {
}, [DynamicComponentLoader, Injector, appElementToken, appComponentAnnotatedTypeToken,
Testability, TestabilityRegistry]),
bind(appChangeDetectorToken).toFactory((ref) => ref.hostView.changeDetector,
[appComponentRefToken]),
bind(appComponentType).toFactory((ref) => ref.instance,
[appComponentRefToken]),
bind(LifeCycle).toFactory((exceptionHandler) => new LifeCycle(exceptionHandler, null, assertionsEnabled()),[ExceptionHandler]),
@ -253,7 +251,7 @@ function _createVmZone(givenReporter:Function): VmTurnZone {
*/
export function bootstrap(appComponentType: Type,
componentInjectableBindings: List<Binding> = null,
errorReporter: Function = null): Promise<ComponentRef> {
errorReporter: Function = null): Promise<ApplicationRef> {
BrowserDomAdapter.makeCurrent();
var bootstrapProcess = PromiseWrapper.completer();
@ -266,13 +264,13 @@ export function bootstrap(appComponentType: Type,
PromiseWrapper.then(appInjector.asyncGet(appComponentRefToken),
(componentRef) => {
var appChangeDetector = componentRef.hostView.changeDetector;
var appChangeDetector = internalView(componentRef.hostView).changeDetector;
// retrieve life cycle: may have already been created if injected in root component
var lc = appInjector.get(LifeCycle);
lc.registerWith(zone, appChangeDetector);
lc.tick(); //the first tick that will bootstrap the app
bootstrapProcess.resolve(componentRef);
bootstrapProcess.resolve(new ApplicationRef(componentRef, appInjector));
},
(err) => {
@ -283,6 +281,28 @@ export function bootstrap(appComponentType: Type,
return bootstrapProcess.promise;
}
export class ApplicationRef {
_hostComponent:ComponentRef;
_injector:Injector;
constructor(hostComponent:ComponentRef, injector:Injector) {
this._hostComponent = hostComponent;
this._injector = injector;
}
get hostComponent() {
return this._hostComponent.instance;
}
dispose() {
// TODO: We also need to clean up the Zone, ... here!
return this._hostComponent.dispose();
}
get injector() {
return this._injector;
}
}
function _createAppInjector(appComponentType: Type, bindings: List<Binding>, zone: VmTurnZone): Injector {
if (isBlank(_rootInjector)) _rootInjector = Injector.resolveAndCreate(_rootBindings);
var mergedBindings = isPresent(bindings) ?

View File

@ -1,7 +1,6 @@
import {OpaqueToken} from 'angular2/di';
export var appComponentRefToken:OpaqueToken = new OpaqueToken('ComponentRef');
export var appChangeDetectorToken:OpaqueToken = new OpaqueToken('AppChangeDetector');
export var appElementToken:OpaqueToken = new OpaqueToken('AppElement');
export var appComponentAnnotatedTypeToken:OpaqueToken = new OpaqueToken('AppComponentAnnotatedType');
export var appDocumentToken:OpaqueToken = new OpaqueToken('AppDocument');

View File

@ -6,6 +6,7 @@ import {List, ListWrapper, Map, MapWrapper} from 'angular2/src/facade/collection
import {DirectiveMetadataReader} from './directive_metadata_reader';
import {Component, Viewport, DynamicComponent, Decorator} from '../annotations/annotations';
import {AppProtoView} from './view';
import {ProtoViewRef} from './view_ref';
import {DirectiveBinding} from './element_injector';
import {TemplateResolver} from './template_resolver';
import {View} from '../annotations/view';
@ -87,21 +88,26 @@ export class Compiler {
// Create a hostView as if the compiler encountered <hostcmp></hostcmp>.
// Used for bootstrapping.
compileInHost(componentTypeOrBinding:any):Promise<AppProtoView> {
compileInHost(componentTypeOrBinding:any):Promise<ProtoViewRef> {
var componentBinding = this._bindDirective(componentTypeOrBinding);
this._assertTypeIsComponent(componentBinding);
var directiveMetadata = Compiler.buildRenderDirective(componentBinding);
return this._renderer.createHostProtoView(directiveMetadata).then( (hostRenderPv) => {
return this._compileNestedProtoViews(null, hostRenderPv, [componentBinding], true);
}).then( (appProtoView) => {
return new ProtoViewRef(appProtoView);
});
}
compile(component: Type):Promise<AppProtoView> {
compile(component: Type):Promise<ProtoViewRef> {
var componentBinding = this._bindDirective(component);
this._assertTypeIsComponent(componentBinding);
var protoView = this._compile(componentBinding);
return PromiseWrapper.isPromise(protoView) ? protoView : PromiseWrapper.resolve(protoView);
var pvPromise = PromiseWrapper.isPromise(protoView) ? protoView : PromiseWrapper.resolve(protoView);
return pvPromise.then( (appProtoView) => {
return new ProtoViewRef(appProtoView);
});
}
// TODO(vicb): union type return AppProtoView or Promise<AppProtoView>

View File

@ -2,9 +2,8 @@ import {Key, Injector, Injectable, ResolvedBinding, Binding, bind} from 'angular
import {Compiler} from './compiler';
import {Type, BaseException, stringify, isPresent} from 'angular2/src/facade/lang';
import {Promise} from 'angular2/src/facade/async';
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
import {ElementRef} from './element_injector';
import {AppView} from './view';
import {AppViewManager, ComponentCreateResult} from 'angular2/src/core/compiler/view_manager';
import {ElementRef} from './element_ref';
/**
* @exportedAs angular2/view
@ -12,22 +11,16 @@ import {AppView} from './view';
export class ComponentRef {
location:ElementRef;
instance:any;
componentView:AppView;
_dispose:Function;
constructor(location:ElementRef, instance:any, componentView:AppView, dispose:Function){
constructor(location:ElementRef, instance:any, dispose:Function) {
this.location = location;
this.instance = instance;
this.componentView = componentView;
this._dispose = dispose;
}
get injector() {
return this.location.injector;
}
get hostView() {
return this.location.hostView;
return this.location.parentView;
}
dispose() {
@ -58,12 +51,12 @@ export class DynamicComponentLoader {
*/
loadIntoExistingLocation(typeOrBinding, location:ElementRef, injector:Injector = null):Promise<ComponentRef> {
var binding = this._getBinding(typeOrBinding);
return this._compiler.compile(binding.token).then(componentProtoView => {
var componentView = this._viewManager.createDynamicComponentView(
location, componentProtoView, binding, injector);
return this._compiler.compile(binding.token).then(componentProtoViewRef => {
this._viewManager.createDynamicComponentView(
location, componentProtoViewRef, binding, injector);
var component = this._viewManager.getComponent(location);
var dispose = () => {throw new BaseException("Not implemented");};
return new ComponentRef(location, location.elementInjector.getDynamicallyLoadedComponent(), componentView, dispose);
return new ComponentRef(location, component, dispose);
});
}
@ -73,16 +66,16 @@ export class DynamicComponentLoader {
*/
loadIntoNewLocation(typeOrBinding, parentComponentLocation:ElementRef, elementOrSelector:any,
injector:Injector = null):Promise<ComponentRef> {
return this._compiler.compileInHost(this._getBinding(typeOrBinding)).then(hostProtoView => {
var hostView = this._viewManager.createInPlaceHostView(
parentComponentLocation, elementOrSelector, hostProtoView, injector);
return this._compiler.compileInHost(this._getBinding(typeOrBinding)).then(hostProtoViewRef => {
var hostViewRef = this._viewManager.createInPlaceHostView(
parentComponentLocation, elementOrSelector, hostProtoViewRef, injector);
var newLocation = new ElementRef(hostViewRef, 0);
var component = this._viewManager.getComponent(newLocation);
var newLocation = hostView.elementInjectors[0].getElementRef();
var component = hostView.elementInjectors[0].getComponent();
var dispose = () => {
this._viewManager.destroyInPlaceHostView(parentComponentLocation, hostView);
this._viewManager.destroyInPlaceHostView(parentComponentLocation, hostViewRef);
};
return new ComponentRef(newLocation, component, hostView.componentChildViews[0], dispose);
return new ComponentRef(newLocation, component, dispose);
});
}
@ -92,16 +85,17 @@ export class DynamicComponentLoader {
*/
loadNextToExistingLocation(typeOrBinding, location:ElementRef, injector:Injector = null):Promise<ComponentRef> {
var binding = this._getBinding(typeOrBinding);
return this._compiler.compileInHost(binding).then(hostProtoView => {
var hostView = location.viewContainer.create(-1, hostProtoView, injector);
return this._compiler.compileInHost(binding).then(hostProtoViewRef => {
var viewContainer = this._viewManager.getViewContainer(location);
var hostViewRef = viewContainer.create(-1, hostProtoViewRef, injector);
var newLocation = new ElementRef(hostViewRef, 0);
var component = this._viewManager.getComponent(newLocation);
var newLocation = hostView.elementInjectors[0].getElementRef();
var component = hostView.elementInjectors[0].getComponent();
var dispose = () => {
var index = location.viewContainer.indexOf(hostView);
location.viewContainer.remove(index);
var index = viewContainer.indexOf(hostViewRef);
viewContainer.remove(index);
};
return new ComponentRef(newLocation, component, hostView.componentChildViews[0], dispose);
return new ComponentRef(newLocation, component, dispose);
});
}

View File

@ -6,10 +6,11 @@ import {Injector, Key, Dependency, bind, Binding, ResolvedBinding, NoBindingErro
AbstractBindingError, CyclicDependencyError} from 'angular2/di';
import {Parent, Ancestor} from 'angular2/src/core/annotations/visibility';
import {Attribute, Query} from 'angular2/src/core/annotations/di';
import * as viewModule from 'angular2/src/core/compiler/view';
import * as viewModule from './view';
import * as avmModule from './view_manager';
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
import {NgElement} from 'angular2/src/core/compiler/ng_element';
import {ViewContainerRef} from './view_container_ref';
import {ElementRef} from './element_ref';
import {ProtoViewRef, ViewRef} from './view_ref';
import {Directive, Component, onChange, onDestroy, onAllChangesDone} from 'angular2/src/core/annotations/annotations';
import {ChangeDetector, ChangeDetectorRef} from 'angular2/change_detection';
import {QueryList} from './query_list';
@ -23,30 +24,9 @@ var _undefined = new Object();
var _staticKeys;
/**
* @exportedAs angular2/view
*/
export class ElementRef {
hostView:viewModule.AppView;
boundElementIndex:number;
injector:Injector;
elementInjector:ElementInjector;
viewContainer:ViewContainerRef;
constructor(elementInjector, hostView, boundElementIndex, injector, viewManager, defaultProtoView){
this.elementInjector = elementInjector;
this.hostView = hostView;
this.boundElementIndex = boundElementIndex;
this.injector = injector;
this.viewContainer = new ViewContainerRef(viewManager, this, defaultProtoView);
}
}
class StaticKeys {
viewManagerId:number;
viewId:number;
ngElementId:number;
defaultProtoViewId:number;
protoViewId:number;
viewContainerId:number;
changeDetectorRefId:number;
elementRefId:number;
@ -54,9 +34,7 @@ class StaticKeys {
constructor() {
//TODO: vsavkin Key.annotate(Key.get(AppView), 'static')
this.viewManagerId = Key.get(avmModule.AppViewManager).id;
this.defaultProtoViewId = Key.get(viewModule.AppProtoView).id;
this.viewId = Key.get(viewModule.AppView).id;
this.ngElementId = Key.get(NgElement).id;
this.protoViewId = Key.get(ProtoViewRef).id;
this.viewContainerId = Key.get(ViewContainerRef).id;
this.changeDetectorRefId = Key.get(ChangeDetectorRef).id;
this.elementRefId = Key.get(ElementRef).id;
@ -294,14 +272,12 @@ export class DirectiveBinding extends ResolvedBinding {
// TODO(rado): benchmark and consider rolling in as ElementInjector fields.
export class PreBuiltObjects {
viewManager:avmModule.AppViewManager;
defaultProtoView:viewModule.AppProtoView;
protoView:viewModule.AppProtoView;
view:viewModule.AppView;
element:NgElement;
constructor(viewManager:avmModule.AppViewManager, view:viewModule.AppView, element:NgElement, defaultProtoView:viewModule.AppProtoView) {
constructor(viewManager:avmModule.AppViewManager, view:viewModule.AppView, protoView:viewModule.AppProtoView) {
this.viewManager = viewManager;
this.view = view;
this.defaultProtoView = defaultProtoView;
this.element = element;
this.protoView = protoView;
}
}
@ -649,11 +625,6 @@ export class ElementInjector extends TreeNode {
return this._proto.eventEmitterAccessors;
}
/** Gets the NgElement associated with this ElementInjector */
getNgElement() {
return this._preBuiltObjects.element;
}
getComponent() {
if (this._proto._binding0IsComponent) {
return this._obj0;
@ -663,8 +634,11 @@ export class ElementInjector extends TreeNode {
}
getElementRef() {
return new ElementRef(this, this._preBuiltObjects.view, this._proto.index, this._lightDomAppInjector,
this._preBuiltObjects.viewManager, this._preBuiltObjects.defaultProtoView);
return new ElementRef(new ViewRef(this._preBuiltObjects.view), this._proto.index);
}
getViewContainerRef() {
return new ViewContainerRef(this._preBuiltObjects.viewManager, this.getElementRef(), new ProtoViewRef(this._preBuiltObjects.protoView));
}
getDynamicallyLoadedComponent() {
@ -742,7 +716,10 @@ export class ElementInjector extends TreeNode {
return this.getElementRef();
}
if (dep.key.id === StaticKeys.instance().viewContainerId) {
return this.getElementRef().viewContainer;
return this.getViewContainerRef();
}
if (dep.key.id === StaticKeys.instance().protoViewId) {
return new ProtoViewRef(this._preBuiltObjects.protoView);
}
return this._getByKey(dep.key, dep.depth, dep.optional, requestor);
}
@ -914,11 +891,7 @@ export class ElementInjector extends TreeNode {
_getPreBuiltObjectByKeyId(keyId:int) {
var staticKeys = StaticKeys.instance();
// TODO: AppView should not be injectable. Remove it.
if (keyId === staticKeys.viewManagerId) return this._preBuiltObjects.viewManagerId;
if (keyId === staticKeys.viewId) return this._preBuiltObjects.view;
if (keyId === staticKeys.ngElementId) return this._preBuiltObjects.element;
if (keyId === staticKeys.defaultProtoViewId) return this._preBuiltObjects.defaultProtoView;
//TODO add other objects as needed
return _undefined;

View File

@ -0,0 +1,40 @@
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';
/**
* @exportedAs angular2/view
*/
export class ElementRef {
parentView:ViewRef;
boundElementIndex:number;
constructor(parentView:ViewRef, boundElementIndex:number) {
this.parentView = parentView;
this.boundElementIndex = boundElementIndex;
}
/**
* Exposes the underlying DOM element.
* (DEPRECATED way of accessing the DOM, replacement coming)
*/
// TODO(tbosch): Here we expose the real DOM element.
// 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];
}
/**
* Gets an attribute from the underlying DOM element.
* (DEPRECATED way of accessing the DOM, replacement coming)
*/
// TODO(tbosch): Here we expose the real DOM element.
// We need a more general way to read/write to the DOM element
// via a proper abstraction in the render layer
getAttribute(name:string):string {
return normalizeBlank(DOM.getAttribute(this.domElement, name));
}
}

View File

@ -1,34 +0,0 @@
import {DOM} from 'angular2/src/dom/dom_adapter';
import {normalizeBlank} from 'angular2/src/facade/lang';
import * as viewModule from '../compiler/view';
import {DirectDomViewRef} from 'angular2/src/render/dom/direct_dom_renderer';
/**
* Allows direct access to the underlying DOM element.
*
* Attention: NgElement will be replaced by a different concept
* for accessing an element in a way that is compatible with the render layer.
*
* @exportedAs angular2/core
*/
export class NgElement {
_view:viewModule.AppView;
_boundElementIndex:number;
constructor(view, boundElementIndex) {
this._view = view;
this._boundElementIndex = boundElementIndex;
}
// TODO(tbosch): Here we expose the real DOM element.
// We need a more general way to read/write to the DOM element
// via a proper abstraction in the render layer
get domElement() {
var domViewRef:DirectDomViewRef = this._view.render;
return domViewRef.delegate.boundElements[this._boundElementIndex];
}
getAttribute(name:string):string {
return normalizeBlank(DOM.getAttribute(this.domElement, name));
}
}

View File

@ -25,7 +25,7 @@ export class AppViewContainer {
// TODO(tbosch): this is not supported in dart2js (no '.' is allowed)
// @IMPLEMENTS(renderApi.EventDispatcher)
export class AppView {
render:renderApi.ViewRef;
render:renderApi.RenderViewRef;
/// This list matches the _nodes list. It is sparse, since only Elements have ElementInjector
rootElementInjectors:List<ElementInjector>;
elementInjectors:List<ElementInjector>;
@ -171,10 +171,10 @@ export class AppProtoView {
_directiveRecordsMap:Map;
_directiveRecords:List;
render:renderApi.ProtoViewRef;
render:renderApi.RenderProtoViewRef;
constructor(
render:renderApi.ProtoViewRef,
render:renderApi.RenderProtoViewRef,
protoChangeDetector:ProtoChangeDetector) {
this.render = render;
this.elementBinders = [];

View File

@ -1,29 +1,27 @@
import {ListWrapper, MapWrapper, List} from 'angular2/src/facade/collection';
import {ListWrapper, List} from 'angular2/src/facade/collection';
import {Injector} from 'angular2/di';
import * as eiModule from 'angular2/src/core/compiler/element_injector';
import {isPresent, isBlank} from 'angular2/src/facade/lang';
import * as viewModule from './view';
import * as avmModule from './view_manager';
/**
* @exportedAs angular2/view
*/
import {ElementRef} from './element_ref';
import {ViewRef, ProtoViewRef, internalView} from './view_ref';
export class ViewContainerRef {
_viewManager: avmModule.AppViewManager;
_location: eiModule.ElementRef;
_defaultProtoView: viewModule.AppProtoView;
_element: ElementRef;
_defaultProtoViewRef: ProtoViewRef;
constructor(viewManager: avmModule.AppViewManager,
location: eiModule.ElementRef,
defaultProtoView: viewModule.AppProtoView) {
element: ElementRef,
defaultProtoViewRef: ProtoViewRef) {
this._viewManager = viewManager;
this._location = location;
this._defaultProtoView = defaultProtoView;
this._element = element;
this._defaultProtoViewRef = defaultProtoViewRef;
}
_getViews() {
var vc = this._location.hostView.viewContainers[this._location.boundElementIndex];
var vc = internalView(this._element.parentView).viewContainers[this._element.boundElementIndex];
return isPresent(vc) ? vc.views : [];
}
@ -33,8 +31,8 @@ export class ViewContainerRef {
}
}
get(index: number): viewModule.AppView {
return this._getViews()[index];
get(index: number): ViewRef {
return new ViewRef(this._getViews()[index]);
}
get length() /* :int */ {
@ -43,26 +41,26 @@ export class ViewContainerRef {
// TODO(rado): profile and decide whether bounds checks should be added
// to the methods below.
create(atIndex:number=-1, protoView:viewModule.AppProtoView = null, injector:Injector = null): viewModule.AppView {
create(atIndex:number=-1, protoViewRef:ProtoViewRef = null, injector:Injector = null): ViewRef {
if (atIndex == -1) atIndex = this.length;
if (isBlank(protoView)) {
protoView = this._defaultProtoView;
if (isBlank(protoViewRef)) {
protoViewRef = this._defaultProtoViewRef;
}
return this._viewManager.createViewInContainer(this._location, atIndex, protoView, injector);
return this._viewManager.createViewInContainer(this._element, atIndex, protoViewRef, injector);
}
insert(view:viewModule.AppView, atIndex:number=-1): viewModule.AppView {
insert(viewRef:ViewRef, atIndex:number=-1): ViewRef {
if (atIndex == -1) atIndex = this.length;
return this._viewManager.attachViewInContainer(this._location, atIndex, view);
return this._viewManager.attachViewInContainer(this._element, atIndex, viewRef);
}
indexOf(view:viewModule.AppView) {
return ListWrapper.indexOf(this._getViews(), view);
indexOf(viewRef:ViewRef) {
return ListWrapper.indexOf(this._getViews(), internalView(viewRef));
}
remove(atIndex:number=-1):void {
if (atIndex == -1) atIndex = this.length - 1;
this._viewManager.destroyViewInContainer(this._location, atIndex);
this._viewManager.destroyViewInContainer(this._element, atIndex);
// view is intentionally not returned to the client.
}
@ -70,8 +68,8 @@ export class ViewContainerRef {
* The method can be used together with insert to implement a view move, i.e.
* moving the dom nodes while the directives in the view stay intact.
*/
detach(atIndex:number=-1): viewModule.AppView {
detach(atIndex:number=-1): ViewRef {
if (atIndex == -1) atIndex = this.length - 1;
return this._viewManager.detachViewInContainer(this._location, atIndex);
return this._viewManager.detachViewInContainer(this._element, atIndex);
}
}
}

View File

@ -1,9 +1,11 @@
import {Injector, Injectable, Binding} from 'angular2/di';
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
import * as eli from './element_injector';
import * as viewModule from './view';
import {Renderer, ViewRef, RenderViewContainerRef} from 'angular2/src/render/api';
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 {AppViewManagerUtils} from './view_manager_utils';
import {AppViewPool} from './view_pool';
@ -24,9 +26,21 @@ export class AppViewManager {
this._utils = utils;
}
createDynamicComponentView(hostLocation:eli.ElementRef,
componentProtoView:viewModule.AppProtoView, componentBinding:Binding, injector:Injector):viewModule.AppView {
var hostView = hostLocation.hostView;
getViewContainer(location:ElementRef):ViewContainerRef {
var hostView = internalView(location.parentView);
return hostView.elementInjectors[location.boundElementIndex].getViewContainerRef();
}
getComponent(hostLocation:ElementRef):any {
var hostView = internalView(hostLocation.parentView);
var boundElementIndex = hostLocation.boundElementIndex;
return this._utils.getComponentInstance(hostView, boundElementIndex);
}
createDynamicComponentView(hostLocation:ElementRef,
componentProtoViewRef:ProtoViewRef, componentBinding:Binding, injector:Injector):ViewRef {
var componentProtoView = internalProtoView(componentProtoViewRef);
var hostView = internalView(hostLocation.parentView);
var boundElementIndex = hostLocation.boundElementIndex;
var binder = hostView.proto.elementBinders[boundElementIndex];
if (!binder.hasDynamicComponent()) {
@ -39,34 +53,36 @@ export class AppViewManager {
this._utils.attachComponentView(hostView, boundElementIndex, componentView);
this._utils.hydrateDynamicComponentInElementInjector(hostView, boundElementIndex, componentBinding, injector);
this._utils.hydrateComponentView(hostView, boundElementIndex);
this._viewHydrateRecurse(componentView, renderViewRefs, 1);
return componentView;
return new ViewRef(componentView);
}
createInPlaceHostView(parentComponentLocation:eli.ElementRef,
hostElementSelector, hostProtoView:viewModule.AppProtoView, injector:Injector):viewModule.AppView {
createInPlaceHostView(parentComponentLocation:ElementRef,
hostElementSelector, hostProtoViewRef:ProtoViewRef, injector:Injector):ViewRef {
var hostProtoView = internalProtoView(hostProtoViewRef);
var parentComponentHostView = null;
var parentComponentBoundElementIndex = null;
var parentRenderViewRef = null;
if (isPresent(parentComponentLocation)) {
parentComponentHostView = parentComponentLocation.hostView;
parentComponentHostView = internalView(parentComponentLocation.parentView);
parentComponentBoundElementIndex = parentComponentLocation.boundElementIndex;
parentRenderViewRef = parentComponentHostView.componentChildViews[parentComponentBoundElementIndex].render;
}
var hostView = this._createViewRecurse(hostProtoView);
var renderViewRefs = this._renderer.createInPlaceHostView(parentRenderViewRef, hostElementSelector, hostView.proto.render);
var renderViewRefs = this._renderer.createInPlaceHostView(parentRenderViewRef, hostElementSelector, hostProtoView.render);
hostView.render = renderViewRefs[0];
this._utils.attachAndHydrateInPlaceHostView(parentComponentHostView, parentComponentBoundElementIndex, hostView, injector);
this._viewHydrateRecurse(hostView, renderViewRefs, 1);
return hostView;
return new ViewRef(hostView);
}
destroyInPlaceHostView(parentComponentLocation:eli.ElementRef, hostView:viewModule.AppView) {
destroyInPlaceHostView(parentComponentLocation:ElementRef, hostViewRef:ViewRef) {
var hostView = internalView(hostViewRef);
var parentView = null;
var parentRenderViewRef = null;
if (isPresent(parentComponentLocation)) {
parentView = parentComponentLocation.hostView.componentChildViews[parentComponentLocation.boundElementIndex];
parentView = internalView(parentComponentLocation.parentView).componentChildViews[parentComponentLocation.boundElementIndex];
parentRenderViewRef = parentView.render;
}
var hostViewRenderRef = hostView.render;
@ -76,10 +92,12 @@ export class AppViewManager {
this._destroyView(hostView);
}
createViewInContainer(viewContainerLocation:eli.ElementRef,
atIndex:number, protoView:viewModule.AppProtoView, injector:Injector = null):viewModule.AppView {
var parentView = viewContainerLocation.hostView;
var boundElementIndex:number = viewContainerLocation.boundElementIndex;
createViewInContainer(viewContainerLocation:ElementRef,
atIndex:number, protoViewRef:ProtoViewRef, injector:Injector = null):ViewRef {
var protoView = internalProtoView(protoViewRef);
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];
@ -87,12 +105,12 @@ export class AppViewManager {
this._utils.attachViewInContainer(parentView, boundElementIndex, atIndex, view);
this._utils.hydrateViewInContainer(parentView, boundElementIndex, atIndex, injector);
this._viewHydrateRecurse(view, renderViewRefs, 1);
return view;
return new ViewRef(view);
}
destroyViewInContainer(viewContainerLocation:eli.ElementRef, atIndex:number) {
var parentView = viewContainerLocation.hostView;
var boundElementIndex:number = viewContainerLocation.boundElementIndex;
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);
@ -101,22 +119,23 @@ export class AppViewManager {
this._destroyView(view);
}
attachViewInContainer(viewContainerLocation:eli.ElementRef, atIndex:number, view:viewModule.AppView):viewModule.AppView {
var parentView = viewContainerLocation.hostView;
var boundElementIndex:number = viewContainerLocation.boundElementIndex;
attachViewInContainer(viewContainerLocation:ElementRef, atIndex:number, viewRef:ViewRef):ViewRef {
var view = internalView(viewRef);
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);
return view;
return viewRef;
}
detachViewInContainer(viewContainerLocation:eli.ElementRef, atIndex:number):viewModule.AppView {
var parentView = viewContainerLocation.hostView;
var boundElementIndex:number = viewContainerLocation.boundElementIndex;
detachViewInContainer(viewContainerLocation:ElementRef, atIndex:number):ViewRef {
var parentView = internalView(viewContainerLocation.parentView);
var boundElementIndex = viewContainerLocation.boundElementIndex;
var viewContainer = parentView.viewContainers[boundElementIndex];
var view = viewContainer.views[atIndex];
this._utils.detachViewInContainer(parentView, boundElementIndex, atIndex);
this._renderer.detachViewFromContainer(this._getRenderViewContainerRef(parentView, boundElementIndex), atIndex);
return view;
return new ViewRef(view);
}
_getRenderViewContainerRef(parentView:viewModule.AppView, boundElementIndex:number) {
@ -145,7 +164,7 @@ export class AppViewManager {
_viewHydrateRecurse(
view:viewModule.AppView,
renderComponentViewRefs:List<ViewRef>,
renderComponentViewRefs:List<RenderViewRef>,
renderComponentIndex:number):number {
this._renderer.setEventDispatcher(view.render, view);

View File

@ -2,7 +2,6 @@ import {Injectable, Injector, Binding} from 'angular2/di';
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
import * as eli from './element_injector';
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
import {NgElement} from 'angular2/src/core/compiler/ng_element';
import * as viewModule from './view';
import * as avmModule from './view_manager';
import {Renderer} from 'angular2/src/render/api';
@ -17,6 +16,16 @@ export class AppViewManagerUtils {
this._metadataReader = metadataReader;
}
getComponentInstance(parentView:viewModule.AppView, boundElementIndex:number):any {
var binder = parentView.proto.elementBinders[boundElementIndex];
var eli = parentView.elementInjectors[boundElementIndex];
if (binder.hasDynamicComponent()) {
return eli.getDynamicallyLoadedComponent();
} else {
return eli.getComponent();
}
}
createView(protoView:viewModule.AppProtoView, viewManager:avmModule.AppViewManager, renderer:Renderer): viewModule.AppView {
var view = new viewModule.AppView(renderer, protoView, protoView.protoLocals);
var changeDetector = protoView.protoChangeDetector.instantiate(view, protoView.bindings,
@ -48,7 +57,7 @@ export class AppViewManagerUtils {
// preBuiltObjects
if (isPresent(elementInjector)) {
var defaultProtoView = isPresent(binder.viewportDirective) ? binder.nestedProtoView : null;
preBuiltObjects[binderIdx] = new eli.PreBuiltObjects(viewManager, view, new NgElement(view, binderIdx), defaultProtoView);
preBuiltObjects[binderIdx] = new eli.PreBuiltObjects(viewManager, view, defaultProtoView);
}
}
@ -74,13 +83,7 @@ export class AppViewManagerUtils {
hydrateComponentView(hostView:viewModule.AppView, boundElementIndex:number, injector:Injector = null) {
var elementInjector = hostView.elementInjectors[boundElementIndex];
var componentView = hostView.componentChildViews[boundElementIndex];
var binder = hostView.proto.elementBinders[boundElementIndex];
var component;
if (binder.hasDynamicComponent()) {
component = elementInjector.getDynamicallyLoadedComponent();
} else {
component = elementInjector.getComponent();
}
var component = this.getComponentInstance(hostView, boundElementIndex);
this._hydrateView(
componentView, injector, elementInjector, component, null
);
@ -106,7 +109,8 @@ export class AppViewManagerUtils {
}
}
attachViewInContainer(parentView:viewModule.AppView, boundElementIndex:number, atIndex:number, view:viewModule.AppView) {
attachViewInContainer(parentView:viewModule.AppView, boundElementIndex:number,
atIndex:number, view:viewModule.AppView) {
parentView.changeDetector.addChild(view.changeDetector);
var viewContainer = parentView.viewContainers[boundElementIndex];
if (isBlank(viewContainer)) {
@ -136,7 +140,8 @@ export class AppViewManagerUtils {
}
}
hydrateViewInContainer(parentView:viewModule.AppView, boundElementIndex:number, atIndex:number, injector:Injector) {
hydrateViewInContainer(parentView:viewModule.AppView, boundElementIndex:number,
atIndex:number, injector:Injector) {
var viewContainer = parentView.viewContainers[boundElementIndex];
var view = viewContainer.views[atIndex];
var elementInjector = parentView.elementInjectors[boundElementIndex];
@ -203,7 +208,7 @@ export class AppViewManagerUtils {
if (elementInjector.isExportingComponent()) {
view.locals.set(exportImplicitName, elementInjector.getComponent());
} else if (elementInjector.isExportingElement()) {
view.locals.set(exportImplicitName, elementInjector.getNgElement().domElement);
view.locals.set(exportImplicitName, elementInjector.getElementRef().domElement);
}
}
}

View File

@ -0,0 +1,43 @@
import {isPresent} from 'angular2/src/facade/lang';
import * as viewModule from './view';
import {RenderViewRef} from 'angular2/src/render/api';
// This is a workaround for privacy in Dart as we don't have library parts
export function internalView(viewRef:ViewRef) {
return viewRef._view;
}
// This is a workaround for privacy in Dart as we don't have library parts
export function internalProtoView(protoViewRef:ProtoViewRef) {
return isPresent(protoViewRef) ? protoViewRef._protoView : null;
}
/**
* @exportedAs angular2/view
*/
export class ViewRef {
_view:viewModule.AppView;
constructor(view:viewModule.AppView) {
this._view = view;
}
get render():RenderViewRef {
return this._view.render;
}
setLocal(contextName: string, value:any) {
this._view.setLocal(contextName, value);
}
}
/**
* @exportedAs angular2/view
*/
export class ProtoViewRef {
_protoView:viewModule.AppProtoView;
constructor(protoView) {
this._protoView = protoView;
}
}