diff --git a/modules/angular2/core.js b/modules/angular2/core.js index 3a6f970937..ca1c4573bb 100644 --- a/modules/angular2/core.js +++ b/modules/angular2/core.js @@ -9,8 +9,8 @@ export * from './src/core/compiler/compiler'; // TODO(tbosch): remove this once render migration is complete export * from 'angular2/src/render/dom/compiler/template_loader'; -export * from './src/core/compiler/private_component_loader'; -export * from './src/core/compiler/private_component_location'; +export * from './src/core/compiler/dynamic_component_loader'; +export {ElementRef, DirectiveRef, ComponetRef} from './src/core/compiler/element_injector'; export * from './src/core/compiler/view'; export * from './src/core/compiler/view_container'; diff --git a/modules/angular2/src/core/annotations/annotations.js b/modules/angular2/src/core/annotations/annotations.js index 48876b2d4b..d8c2d99429 100644 --- a/modules/angular2/src/core/annotations/annotations.js +++ b/modules/angular2/src/core/annotations/annotations.js @@ -590,7 +590,7 @@ export class Component extends Directive { * }) * class DynamicComp { * helloCmp:HelloCmp; - * constructor(loader:PrivateComponentLoader, location:PrivateComponentLocation) { + * constructor(loader:DynamicComponentLoader, location:PrivateComponentLocation) { * loader.load(HelloCmp, location).then((helloCmp) => { * this.helloCmp = helloCmp; * }); diff --git a/modules/angular2/src/core/application.js b/modules/angular2/src/core/application.js index 920b2f3cbf..b9be9110da 100644 --- a/modules/angular2/src/core/application.js +++ b/modules/angular2/src/core/application.js @@ -24,8 +24,7 @@ import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mappe import {UrlResolver} from 'angular2/src/services/url_resolver'; import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver'; import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner'; -import {Component} from 'angular2/src/core/annotations/annotations'; -import {PrivateComponentLoader} from 'angular2/src/core/compiler/private_component_loader'; +import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader'; import {TestabilityRegistry, Testability} from 'angular2/src/core/testability/testability'; import {ViewFactory, VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_factory'; import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory'; @@ -35,7 +34,7 @@ import * as rc from 'angular2/src/render/dom/compiler/compiler'; import * as rvf from 'angular2/src/render/dom/view/view_factory'; import { - appViewToken, + appComponentRefToken, appChangeDetectorToken, appElementToken, appComponentAnnotatedTypeToken, @@ -66,37 +65,20 @@ function _injectorBindings(appComponentType): List { } return element; }, [appComponentAnnotatedTypeToken, appDocumentToken]), - bind(appViewToken).toAsyncFactory((changeDetection, compiler, injector, appElement, - appComponentAnnotatedType, testability, registry, viewFactory) => { + bind(appComponentRefToken).toAsyncFactory((dynamicComponentLoader, injector, appElement, + 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); - var annotation = appComponentAnnotatedType.annotation; - if(!isBlank(annotation) && !(annotation instanceof Component)) { - var type = appComponentAnnotatedType.type; - throw new BaseException(`Only Components can be bootstrapped; ` + - `Directive of ${stringify(type)} is not a Component`); - } - return compiler.compileRoot( - appElement, - appComponentAnnotatedType.type - ).then( - (appProtoView) => { - // The light Dom of the app element is not considered part of - // the angular application. Thus the context and lightDomInjector are - // empty. - var view = viewFactory.getView(appProtoView); - view.hydrate(injector, null, new Object(), null); - return view; - }); - }, [ChangeDetection, Compiler, Injector, appElementToken, appComponentAnnotatedTypeToken, - Testability, TestabilityRegistry, ViewFactory]), + return dynamicComponentLoader.loadIntoNewLocation(appElement, appComponentAnnotatedType.type, null, injector); + }, [DynamicComponentLoader, Injector, appElementToken, appComponentAnnotatedTypeToken, + Testability, TestabilityRegistry]), - bind(appChangeDetectorToken).toFactory((rootView) => rootView.changeDetector, - [appViewToken]), - bind(appComponentType).toFactory((rootView) => rootView.elementInjectors[0].getComponent(), - [appViewToken]), + 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]), bind(EventManager).toFactory((zone) => { var plugins = [new HammerGesturesPlugin(), new DomEventsPlugin()]; @@ -136,8 +118,8 @@ function _injectorBindings(appComponentType): List { UrlResolver, StyleUrlResolver, StyleInliner, - PrivateComponentLoader, - Testability, + DynamicComponentLoader, + Testability ]; } @@ -260,8 +242,8 @@ function _createVmZone(givenReporter:Function): VmTurnZone { * @publicModule angular2/angular2 */ export function bootstrap(appComponentType: Type, - componentServiceBindings: List=null, - errorReporter: Function=null): Promise { + componentServiceBindings: List = null, + errorReporter: Function = null): Promise { BrowserDomAdapter.makeCurrent(); var bootstrapProcess = PromiseWrapper.completer(); @@ -272,11 +254,11 @@ export function bootstrap(appComponentType: Type, var appInjector = _createAppInjector(appComponentType, componentServiceBindings, zone); - PromiseWrapper.then(appInjector.asyncGet(appViewToken), - (rootView) => { + PromiseWrapper.then(appInjector.asyncGet(appChangeDetectorToken), + (appChangeDetector) => { // retrieve life cycle: may have already been created if injected in root component - var lc=appInjector.get(LifeCycle); - lc.registerWith(zone, rootView.changeDetector); + var lc = appInjector.get(LifeCycle); + lc.registerWith(zone, appChangeDetector); lc.tick(); //the first tick that will bootstrap the app bootstrapProcess.resolve(appInjector); diff --git a/modules/angular2/src/core/application_tokens.js b/modules/angular2/src/core/application_tokens.js index 9f0004b1ef..0850a1b085 100644 --- a/modules/angular2/src/core/application_tokens.js +++ b/modules/angular2/src/core/application_tokens.js @@ -1,6 +1,6 @@ import {OpaqueToken} from 'angular2/di'; -export var appViewToken = new OpaqueToken('AppView'); +export var appComponentRefToken = new OpaqueToken('ComponentRef'); export var appChangeDetectorToken = new OpaqueToken('AppChangeDetector'); export var appElementToken = new OpaqueToken('AppElement'); export var appComponentAnnotatedTypeToken = new OpaqueToken('AppComponentAnnotatedType'); diff --git a/modules/angular2/src/core/compiler/dynamic_component_loader.js b/modules/angular2/src/core/compiler/dynamic_component_loader.js new file mode 100644 index 0000000000..1e56682129 --- /dev/null +++ b/modules/angular2/src/core/compiler/dynamic_component_loader.js @@ -0,0 +1,99 @@ +import {Key, Injector, Injectable} from 'angular2/di' +import {Compiler} from './compiler'; +import {DirectiveMetadataReader} from './directive_metadata_reader'; +import {Type, BaseException, stringify, isPresent} from 'angular2/src/facade/lang'; +import {Promise} from 'angular2/src/facade/async'; +import {Component} from 'angular2/src/core/annotations/annotations'; +import {ViewFactory} from 'angular2/src/core/compiler/view_factory'; +import {Renderer} from 'angular2/src/render/api'; +import {ElementRef, DirectiveRef, ComponentRef} from './element_injector'; + +/** + * Service for dynamically loading a Component into an arbitrary position in the internal Angular + * application tree. + */ +@Injectable() +export class DynamicComponentLoader { + _compiler:Compiler; + _viewFactory:ViewFactory; + _renderer:Renderer; + _directiveMetadataReader:DirectiveMetadataReader; + + constructor(compiler:Compiler, directiveMetadataReader:DirectiveMetadataReader, + renderer:Renderer, viewFactory:ViewFactory) { + this._compiler = compiler; + this._directiveMetadataReader = directiveMetadataReader; + this._renderer = renderer; + this._viewFactory = viewFactory + } + + /** + * Loads a component into the location given by the provided ElementRef. The loaded component + * receives injection as if it in the place of the provided ElementRef. + */ + loadIntoExistingLocation(type:Type, location:ElementRef, injector:Injector = null):Promise { + this._assertTypeIsComponent(type); + + var annotation = this._directiveMetadataReader.read(type).annotation; + + var inj = this._componentAppInjector(location, injector, annotation.services); + + var hostEi = location.elementInjector; + var hostView = location.hostView; + + return this._compiler.compile(type).then(componentProtoView => { + var context = hostEi.dynamicallyCreateComponent(type, annotation, inj); + var componentView = this._instantiateAndHydrateView(componentProtoView, injector, hostEi, context); + + //TODO(vsavkin): do not use component child views as we need to clear the dynamically created views + //same problem exists on the render side + hostView.addComponentChildView(componentView); + + this._renderer.setDynamicComponentView(hostView.render, location.boundElementIndex, componentView.render); + + // TODO(vsavkin): return a component ref that dehydrates the component view and removes it + // from the component child views + return new ComponentRef(Key.get(type), hostEi, componentView); + }); + } + + /** + * Loads a component as a child of the View given by the provided ElementRef. The loaded + * component receives injection normally as a hosted view. + * + * TODO(vsavkin, jelbourn): remove protoViewFactory after render layer exists. + */ + loadIntoNewLocation(elementOrSelector:any, type:Type, location:ElementRef, + injector:Injector = null):Promise { + this._assertTypeIsComponent(type); + + var inj = this._componentAppInjector(location, injector, null); + + //TODO(tbosch) this should always be a selector + return this._compiler.compileRoot(elementOrSelector, type).then(pv => { + var hostView = this._instantiateAndHydrateView(pv, inj, null, new Object()); + + // TODO(vsavkin): return a component ref that dehydrates the host view + return new ComponentRef(Key.get(type), hostView.elementInjectors[0], hostView.componentChildViews[0]); + }); + } + + _componentAppInjector(location, injector, services) { + var inj = isPresent(injector) ? injector : location.elementInjector.getLightDomAppInjector(); + return isPresent(services) ? inj.createChild(services) : inj; + } + + _instantiateAndHydrateView(protoView, injector, hostElementInjector, context) { + var componentView = this._viewFactory.getView(protoView); + componentView.hydrate(injector, hostElementInjector, context, null); + return componentView; + } + + /** Asserts that the type being dynamically instantiated is a Component. */ + _assertTypeIsComponent(type:Type) { + var annotation = this._directiveMetadataReader.read(type).annotation; + if (!(annotation instanceof Component)) { + throw new BaseException(`Could not load '${stringify(type)}' because it is not a component.`); + } + } +} \ No newline at end of file diff --git a/modules/angular2/src/core/compiler/element_injector.js b/modules/angular2/src/core/compiler/element_injector.js index 87301696fd..d99de3049a 100644 --- a/modules/angular2/src/core/compiler/element_injector.js +++ b/modules/angular2/src/core/compiler/element_injector.js @@ -9,7 +9,6 @@ import {ViewContainer} from 'angular2/src/core/compiler/view_container'; import {NgElement} from 'angular2/src/core/compiler/ng_element'; import {Directive, onChange, onDestroy, onAllChangesDone} from 'angular2/src/core/annotations/annotations'; import {BindingPropagationConfig} from 'angular2/change_detection'; -import * as pclModule from 'angular2/src/core/compiler/private_component_location'; import {QueryList} from './query_list'; var _MAX_DIRECTIVE_CONSTRUCTION_COUNTER = 10; @@ -20,12 +19,50 @@ var _undefined = new Object(); var _staticKeys; +export class ElementRef { + elementInjector:ElementInjector; + + constructor(elementInjector:ElementInjector){ + this.elementInjector = elementInjector; + } + + get hostView() { + return this.elementInjector.getHostView(); + } + + get boundElementIndex() { + return this.elementInjector.getBoundElementIndex(); + } +} + +export class DirectiveRef extends ElementRef { + _key:Key; + + constructor(key:Key, elementInjector:ElementInjector){ + super(elementInjector); + this._key = key; + } + + get instance() { + return this.elementInjector.get(this._key); + } +} + +export class ComponentRef extends DirectiveRef { + componentView:viewModule.View; + + constructor(key:Key, elementInjector:ElementInjector, componentView:viewModule.View){ + super(key, elementInjector); + this.componentView = componentView; + } +} + class StaticKeys { viewId:number; ngElementId:number; viewContainerId:number; bindingPropagationConfigId:number; - privateComponentLocationId:number; + directiveRefId:number; constructor() { //TODO: vsavkin Key.annotate(Key.get(View), 'static') @@ -33,7 +70,7 @@ class StaticKeys { this.ngElementId = Key.get(NgElement).id; this.viewContainerId = Key.get(ViewContainer).id; this.bindingPropagationConfigId = Key.get(BindingPropagationConfig).id; - this.privateComponentLocationId = Key.get(pclModule.PrivateComponentLocation).id; + this.directiveRefId = Key.get(DirectiveRef).id; } static instance() { @@ -200,32 +237,40 @@ export class DirectiveDependency extends Dependency { } static createFrom(d:Dependency):Dependency { - var depth = 0; - var eventName = null; - var propName = null; - var attributeName = null; - var properties = d.properties; - var queryDirective = null; + return new DirectiveDependency(d.key, d.asPromise, d.lazy, d.optional, + d.properties, DirectiveDependency._depth(d.properties), + DirectiveDependency._eventEmitterName(d.properties), + DirectiveDependency._propSetterName(d.properties), + DirectiveDependency._attributeName(d.properties), + DirectiveDependency._query(d.properties) + ); + } - for (var i = 0; i < properties.length; i++) { - var property = properties[i]; - if (property instanceof Parent) { - depth = 1; - } else if (property instanceof Ancestor) { - depth = MAX_DEPTH; - } else if (property instanceof EventEmitter) { - eventName = property.eventName; - } else if (property instanceof PropertySetter) { - propName = property.propName; - } else if (property instanceof Attribute) { - attributeName = property.attributeName; - } else if (property instanceof Query) { - queryDirective = property.directive; - } - } + static _depth(properties):int { + if (properties.length == 0) return 0; + if (ListWrapper.any(properties, p => p instanceof Parent)) return 1; + if (ListWrapper.any(properties, p => p instanceof Ancestor)) return MAX_DEPTH; + return 0; + } - return new DirectiveDependency(d.key, d.asPromise, d.lazy, d.optional, d.properties, depth, - eventName, propName, attributeName, queryDirective); + static _eventEmitterName(properties):string { + var p = ListWrapper.find(properties, (p) => p instanceof EventEmitter); + return isPresent(p) ? p.eventName : null; + } + + static _propSetterName(properties):string { + var p = ListWrapper.find(properties, (p) => p instanceof PropertySetter); + return isPresent(p) ? p.propName : null; + } + + static _attributeName(properties):string { + var p = ListWrapper.find(properties, (p) => p instanceof Attribute); + return isPresent(p) ? p.attributeName : null; + } + + static _query(properties) { + var p = ListWrapper.find(properties, (p) => p instanceof Query); + return isPresent(p) ? p.directive : null; } } @@ -425,6 +470,8 @@ export class ElementInjector extends TreeNode { _lightDomAppInjector:Injector; _shadowDomAppInjector:Injector; _host:ElementInjector; + + // If this element injector has a component, the component instance will be stored in _obj0 _obj0:any; _obj1:any; _obj2:any; @@ -437,8 +484,9 @@ export class ElementInjector extends TreeNode { _obj9:any; _preBuiltObjects; _constructionCounter; - _privateComponent; - _privateComponentBinding:DirectiveBinding; + + _dynamicallyCreatedComponent:any; + _dynamicallyCreatedComponentBinding:DirectiveBinding; // Queries are added during construction or linking with a new parent. // They are never removed. @@ -450,7 +498,6 @@ export class ElementInjector extends TreeNode { this._proto = proto; //we cannot call clearDirectives because fields won't be detected - this._host = null; this._preBuiltObjects = null; this._lightDomAppInjector = null; this._shadowDomAppInjector = null; @@ -488,8 +535,8 @@ export class ElementInjector extends TreeNode { if (isPresent(p._binding7) && p._binding7.callOnDestroy) {this._obj7.onDestroy();} if (isPresent(p._binding8) && p._binding8.callOnDestroy) {this._obj8.onDestroy();} if (isPresent(p._binding9) && p._binding9.callOnDestroy) {this._obj9.onDestroy();} - if (isPresent(this._privateComponentBinding) && this._privateComponentBinding.callOnDestroy) { - this._privateComponent.onDestroy(); + if (isPresent(this._dynamicallyCreatedComponentBinding) && this._dynamicallyCreatedComponentBinding.callOnDestroy) { + this._dynamicallyCreatedComponent.onDestroy(); } this._obj0 = null; @@ -502,7 +549,8 @@ export class ElementInjector extends TreeNode { this._obj7 = null; this._obj8 = null; this._obj9 = null; - this._privateComponent = null; + this._dynamicallyCreatedComponent = null; + this._dynamicallyCreatedComponentBinding = null; this._constructionCounter = 0; } @@ -526,15 +574,13 @@ export class ElementInjector extends TreeNode { if (isPresent(p._keyId7)) this._getDirectiveByKeyId(p._keyId7); if (isPresent(p._keyId8)) this._getDirectiveByKeyId(p._keyId8); if (isPresent(p._keyId9)) this._getDirectiveByKeyId(p._keyId9); - if (isPresent(this._privateComponentBinding)) { - this._privateComponent = this._new(this._privateComponentBinding); - } } - createPrivateComponent(componentType:Type, annotation:Directive) { - this._privateComponentBinding = DirectiveBinding.createFromType(componentType, annotation); - this._privateComponent = this._new(this._privateComponentBinding); - return this._privateComponent; + dynamicallyCreateComponent(componentType:Type, annotation:Directive, injector:Injector) { + this._shadowDomAppInjector = injector; + this._dynamicallyCreatedComponentBinding = DirectiveBinding.createFromType(componentType, annotation); + this._dynamicallyCreatedComponent = this._new(this._dynamicallyCreatedComponentBinding); + return this._dynamicallyCreatedComponent; } _checkShadowDomAppInjector(shadowDomAppInjector:Injector) { @@ -546,9 +592,18 @@ export class ElementInjector extends TreeNode { } get(token) { + if (this._isDynamicallyLoadedComponent(token)) { + return this._dynamicallyCreatedComponent; + } + return this._getByKey(Key.get(token), 0, false, null); } + _isDynamicallyLoadedComponent(token) { + return isPresent(this._dynamicallyCreatedComponentBinding) && + Key.get(token) === this._dynamicallyCreatedComponentBinding.key; + } + hasDirective(type:Type):boolean { return this._getDirectiveByKeyId(Key.get(type).id) !== _undefined; } @@ -563,20 +618,25 @@ export class ElementInjector extends TreeNode { return this._preBuiltObjects.element; } + /** Gets the View associated with this ElementInjector */ + getHostView() { + return this._preBuiltObjects.view; + } + getComponent() { if (this._proto._binding0IsComponent) { return this._obj0; } else { - throw new BaseException('There is not component stored in this ElementInjector'); + throw new BaseException('There is no component stored in this ElementInjector'); } } - getPrivateComponent() { - return this._privateComponent; + getDynamicallyLoadedComponent() { + return this._dynamicallyCreatedComponent; } - getShadowDomAppInjector() { - return this._shadowDomAppInjector; + getLightDomAppInjector() { + return this._lightDomAppInjector; } directParent(): ElementInjector { @@ -587,8 +647,9 @@ export class ElementInjector extends TreeNode { return this._proto._binding0IsComponent && key.id === this._proto._keyId0; } - _isPrivateComponentKey(key:Key) { - return isPresent(this._privateComponentBinding) && key.id === this._privateComponentBinding.key.id; + _isDynamicallyLoadedComponentKey(key:Key) { + return isPresent(this._dynamicallyCreatedComponentBinding) && key.id === + this._dynamicallyCreatedComponentBinding.key.id; } _new(binding:Binding) { @@ -647,6 +708,10 @@ export class ElementInjector extends TreeNode { if (isPresent(dep.propSetterName)) return this._buildPropSetter(dep); if (isPresent(dep.attributeName)) return this._buildAttribute(dep); if (isPresent(dep.queryDirective)) return this._findQuery(dep.queryDirective).list; + if (dep.key.id === StaticKeys.instance().directiveRefId) { + // TODO: we need store component view here and pass it to directive ref + return new DirectiveRef(requestor, this); + } return this._getByKey(dep.key, dep.depth, dep.optional, requestor); } @@ -819,10 +884,11 @@ export class ElementInjector extends TreeNode { ei = ei._parent; } + if (isPresent(this._host) && this._host._isComponentKey(key)) { return this._host.getComponent(); - } else if (isPresent(this._host) && this._host._isPrivateComponentKey(key)) { - return this._host.getPrivateComponent(); + } else if (isPresent(this._host) && this._host._isDynamicallyLoadedComponentKey(key)) { + return this._host.getDynamicallyLoadedComponent(); } else if (optional) { return this._appInjector(requestor).getOptional(key); } else { @@ -831,7 +897,7 @@ export class ElementInjector extends TreeNode { } _appInjector(requestor:Key) { - if (isPresent(requestor) && this._isComponentKey(requestor)) { + if (isPresent(requestor) && (this._isComponentKey(requestor) || this._isDynamicallyLoadedComponentKey(requestor))) { return this._shadowDomAppInjector; } else { return this._lightDomAppInjector; @@ -850,10 +916,6 @@ export class ElementInjector extends TreeNode { if (keyId === staticKeys.viewContainerId) return this._preBuiltObjects.viewContainer; if (keyId === staticKeys.bindingPropagationConfigId) return this._preBuiltObjects.bindingPropagationConfig; - if (keyId === staticKeys.privateComponentLocationId) { - return new pclModule.PrivateComponentLocation(this, this._preBuiltObjects.view); - } - //TODO add other objects as needed return _undefined; } diff --git a/modules/angular2/src/core/compiler/private_component_loader.js b/modules/angular2/src/core/compiler/private_component_loader.js deleted file mode 100644 index 49da82bd18..0000000000 --- a/modules/angular2/src/core/compiler/private_component_loader.js +++ /dev/null @@ -1,38 +0,0 @@ -import {Compiler} from './compiler'; -import {ViewFactory} from './view_factory'; -import {Injectable} from 'angular2/di'; -import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; -import {Component} from 'angular2/src/core/annotations/annotations'; -import {PrivateComponentLocation} from './private_component_location'; -import {Type, stringify, BaseException} from 'angular2/src/facade/lang'; - - -@Injectable() -export class PrivateComponentLoader { - compiler:Compiler; - directiveMetadataReader:DirectiveMetadataReader; - viewFactory:ViewFactory; - - constructor(compiler:Compiler, directiveMetadataReader:DirectiveMetadataReader, viewFactory:ViewFactory) { - - this.compiler = compiler; - this.directiveMetadataReader = directiveMetadataReader; - this.viewFactory = viewFactory; - } - - load(type:Type, location:PrivateComponentLocation) { - var annotation = this.directiveMetadataReader.read(type).annotation; - - if (!(annotation instanceof Component)) { - throw new BaseException(`Could not load '${stringify(type)}' because it is not a component.`); - } - - return this.compiler.compile(type).then((componentProtoView) => { - location.createComponent( - this.viewFactory, - type, annotation, - componentProtoView - ); - }); - } -} diff --git a/modules/angular2/src/core/compiler/private_component_location.js b/modules/angular2/src/core/compiler/private_component_location.js deleted file mode 100644 index e8282be9da..0000000000 --- a/modules/angular2/src/core/compiler/private_component_location.js +++ /dev/null @@ -1,29 +0,0 @@ -import {Directive} from 'angular2/src/core/annotations/annotations' -import * as viewModule from './view'; -import * as eiModule from './element_injector'; -import {ListWrapper} from 'angular2/src/facade/collection'; -import {Type} from 'angular2/src/facade/lang'; -import * as vfModule from './view_factory'; - -export class PrivateComponentLocation { - _elementInjector:eiModule.ElementInjector; - _view:viewModule.View; - - constructor(elementInjector:eiModule.ElementInjector, view:viewModule.View){ - this._elementInjector = elementInjector; - this._view = view; - } - - createComponent(viewFactory: vfModule.ViewFactory, type:Type, annotation:Directive, componentProtoView:viewModule.ProtoView) { - var context = this._elementInjector.createPrivateComponent(type, annotation); - - var view = viewFactory.getView(componentProtoView); - view.hydrate(this._elementInjector.getShadowDomAppInjector(), this._elementInjector, context, null); - - this._view.proto.renderer.setDynamicComponentView( - this._view.render, this._elementInjector.getBoundElementIndex(), view.render - ); - ListWrapper.push(this._view.componentChildViews, view); - this._view.changeDetector.addChild(view.changeDetector); - } -} diff --git a/modules/angular2/src/core/compiler/view.js b/modules/angular2/src/core/compiler/view.js index 540030abc7..99d20781eb 100644 --- a/modules/angular2/src/core/compiler/view.js +++ b/modules/angular2/src/core/compiler/view.js @@ -28,7 +28,18 @@ export class View { viewContainers: List; preBuiltObjects: List; proto: ProtoView; + + /** + * The context against which data-binding expressions in this view are evaluated against. + * This is always a component instance. + */ context: any; + + /** + * Variables, local to this view, that can be used in binding expressions (in addition to the + * context). This is used for thing like `