@ -13,3 +13,16 @@ export class EventEmitter extends DependencyAnnotation {
|
||||
this.eventName = eventName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The directive can inject a property setter that would allow setting this property on the
|
||||
* host element
|
||||
*/
|
||||
export class PropertySetter extends DependencyAnnotation {
|
||||
propName: string;
|
||||
@CONST()
|
||||
constructor(propName) {
|
||||
super();
|
||||
this.propName = propName;
|
||||
}
|
||||
}
|
6
modules/angular2/src/core/application.js
vendored
6
modules/angular2/src/core/application.js
vendored
@ -59,7 +59,7 @@ function _injectorBindings(appComponentType): List<Binding> {
|
||||
}, [appComponentAnnotatedTypeToken, appDocumentToken]),
|
||||
|
||||
bind(appViewToken).toAsyncFactory((changeDetection, compiler, injector, appElement,
|
||||
appComponentAnnotatedType, strategy, eventManager) => {
|
||||
appComponentAnnotatedType, strategy, eventManager, reflector) => {
|
||||
return compiler.compile(appComponentAnnotatedType.type).then(
|
||||
(protoView) => {
|
||||
var appProtoView = ProtoView.createRootProtoView(protoView, appElement,
|
||||
@ -68,12 +68,12 @@ function _injectorBindings(appComponentType): List<Binding> {
|
||||
// The light Dom of the app element is not considered part of
|
||||
// the angular application. Thus the context and lightDomInjector are
|
||||
// empty.
|
||||
var view = appProtoView.instantiate(null, eventManager);
|
||||
var view = appProtoView.instantiate(null, eventManager, reflector);
|
||||
view.hydrate(injector, null, new Object());
|
||||
return view;
|
||||
});
|
||||
}, [ChangeDetection, Compiler, Injector, appElementToken, appComponentAnnotatedTypeToken,
|
||||
ShadowDomStrategy, EventManager]),
|
||||
ShadowDomStrategy, EventManager, Reflector]),
|
||||
|
||||
bind(appChangeDetectorToken).toFactory((rootView) => rootView.changeDetector,
|
||||
[appViewToken]),
|
||||
|
@ -3,13 +3,14 @@ import {Math} from 'angular2/src/facade/math';
|
||||
import {List, ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
|
||||
import {Injector, Key, Dependency, bind, Binding, NoProviderError, ProviderError, CyclicDependencyError} from 'angular2/di';
|
||||
import {Parent, Ancestor} from 'angular2/src/core/annotations/visibility';
|
||||
import {EventEmitter} from 'angular2/src/core/annotations/events';
|
||||
import {EventEmitter, PropertySetter} from 'angular2/src/core/annotations/di';
|
||||
import {View, ProtoView} from 'angular2/src/core/compiler/view';
|
||||
import {LightDom, SourceLightDom, DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
|
||||
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
||||
import {NgElement} from 'angular2/src/core/dom/element';
|
||||
import {Directive, onChange, onDestroy} from 'angular2/src/core/annotations/annotations'
|
||||
import {BindingPropagationConfig} from 'angular2/src/core/compiler/binding_propagation_config'
|
||||
import {Reflector} from 'angular2/src/reflection/reflection';
|
||||
|
||||
var _MAX_DIRECTIVE_CONSTRUCTION_COUNTER = 10;
|
||||
|
||||
@ -90,18 +91,22 @@ class TreeNode {
|
||||
export class DirectiveDependency extends Dependency {
|
||||
depth:int;
|
||||
eventEmitterName:string;
|
||||
propSetterName:string;
|
||||
|
||||
constructor(key:Key, asPromise:boolean, lazy:boolean, optional:boolean,
|
||||
properties:List, depth:int, eventEmitterName: string) {
|
||||
properties:List, depth:int, eventEmitterName: string, propSetterName: string) {
|
||||
super(key, asPromise, lazy, optional, properties);
|
||||
this.depth = depth;
|
||||
this.eventEmitterName = eventEmitterName;
|
||||
this.propSetterName = propSetterName;
|
||||
}
|
||||
|
||||
static createFrom(d:Dependency):Dependency {
|
||||
return new DirectiveDependency(d.key, d.asPromise, d.lazy, d.optional,
|
||||
d.properties, DirectiveDependency._depth(d.properties),
|
||||
DirectiveDependency._eventEmitterName(d.properties));
|
||||
DirectiveDependency._eventEmitterName(d.properties),
|
||||
DirectiveDependency._propSetterName(d.properties)
|
||||
);
|
||||
}
|
||||
|
||||
static _depth(properties):int {
|
||||
@ -119,6 +124,15 @@ export class DirectiveDependency extends Dependency {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static _propSetterName(properties):string {
|
||||
for (var i = 0; i < properties.length; i++) {
|
||||
if (properties[i] instanceof PropertySetter) {
|
||||
return properties[i].propName;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export class DirectiveBinding extends Binding {
|
||||
@ -256,8 +270,9 @@ export class ProtoElementInjector {
|
||||
}
|
||||
}
|
||||
|
||||
instantiate(parent:ElementInjector, host:ElementInjector, eventCallbacks):ElementInjector {
|
||||
return new ElementInjector(this, parent, host, eventCallbacks);
|
||||
instantiate(parent:ElementInjector, host:ElementInjector, eventCallbacks,
|
||||
reflector: Reflector):ElementInjector {
|
||||
return new ElementInjector(this, parent, host, eventCallbacks, reflector);
|
||||
}
|
||||
|
||||
directParent(): ProtoElementInjector {
|
||||
@ -311,7 +326,10 @@ export class ElementInjector extends TreeNode {
|
||||
_preBuiltObjects;
|
||||
_constructionCounter;
|
||||
_eventCallbacks;
|
||||
constructor(proto:ProtoElementInjector, parent:ElementInjector, host:ElementInjector, eventCallbacks: Map) {
|
||||
_refelector: Reflector;
|
||||
|
||||
constructor(proto:ProtoElementInjector, parent:ElementInjector, host:ElementInjector,
|
||||
eventCallbacks: Map, reflector: Reflector) {
|
||||
super(parent);
|
||||
if (isPresent(parent) && isPresent(host)) {
|
||||
throw new BaseException('Only either parent or host is allowed');
|
||||
@ -324,6 +342,7 @@ export class ElementInjector extends TreeNode {
|
||||
}
|
||||
|
||||
this._proto = proto;
|
||||
this._refelector = reflector;
|
||||
|
||||
//we cannot call clearDirectives because fields won't be detected
|
||||
this._preBuiltObjects = null;
|
||||
@ -488,6 +507,7 @@ export class ElementInjector extends TreeNode {
|
||||
|
||||
_getByDependency(dep:DirectiveDependency, requestor:Key) {
|
||||
if (isPresent(dep.eventEmitterName)) return this._buildEventEmitter(dep);
|
||||
if (isPresent(dep.propSetterName)) return this._buildPropSetter(dep);
|
||||
return this._getByKey(dep.key, dep.depth, dep.optional, requestor);
|
||||
}
|
||||
|
||||
@ -502,6 +522,13 @@ export class ElementInjector extends TreeNode {
|
||||
return (_) => {};
|
||||
}
|
||||
|
||||
_buildPropSetter(dep) {
|
||||
var ngElement = this._getPreBuiltObjectByKeyId(StaticKeys.instance().ngElementId);
|
||||
var domElement = ngElement.domElement;
|
||||
var setter = this._refelector.setter(dep.propSetterName);
|
||||
return function(v) { setter(domElement, v) };
|
||||
}
|
||||
|
||||
/*
|
||||
* It is fairly easy to annotate keys with metadata.
|
||||
* For example, key.metadata = 'directive'.
|
||||
|
28
modules/angular2/src/core/compiler/view.js
vendored
28
modules/angular2/src/core/compiler/view.js
vendored
@ -18,6 +18,8 @@ import {ShadowDomStrategy} from './shadow_dom_strategy';
|
||||
import {ViewPool} from './view_pool';
|
||||
import {EventManager} from 'angular2/src/core/events/event_manager';
|
||||
|
||||
import {Reflector} from 'angular2/src/reflection/reflection';
|
||||
|
||||
const NG_BINDING_CLASS = 'ng-binding';
|
||||
const NG_BINDING_CLASS_SELECTOR = '.ng-binding';
|
||||
|
||||
@ -298,19 +300,23 @@ export class ProtoView {
|
||||
}
|
||||
|
||||
// TODO(rado): hostElementInjector should be moved to hydrate phase.
|
||||
instantiate(hostElementInjector: ElementInjector, eventManager: EventManager):View {
|
||||
if (this._viewPool.length() == 0) this._preFillPool(hostElementInjector, eventManager);
|
||||
instantiate(hostElementInjector: ElementInjector, eventManager: EventManager,
|
||||
reflector: Reflector):View {
|
||||
if (this._viewPool.length() == 0) this._preFillPool(hostElementInjector, eventManager,
|
||||
reflector);
|
||||
var view = this._viewPool.pop();
|
||||
return isPresent(view) ? view : this._instantiate(hostElementInjector, eventManager);
|
||||
return isPresent(view) ? view : this._instantiate(hostElementInjector, eventManager, reflector);
|
||||
}
|
||||
|
||||
_preFillPool(hostElementInjector: ElementInjector, eventManager: EventManager) {
|
||||
_preFillPool(hostElementInjector: ElementInjector, eventManager: EventManager,
|
||||
reflector: Reflector) {
|
||||
for (var i = 0; i < VIEW_POOL_PREFILL; i++) {
|
||||
this._viewPool.push(this._instantiate(hostElementInjector, eventManager));
|
||||
this._viewPool.push(this._instantiate(hostElementInjector, eventManager, reflector));
|
||||
}
|
||||
}
|
||||
|
||||
_instantiate(hostElementInjector: ElementInjector, eventManager: EventManager): View {
|
||||
_instantiate(hostElementInjector: ElementInjector, eventManager: EventManager,
|
||||
reflector: Reflector): View {
|
||||
var rootElementClone = this.instantiateInPlace ? this.element : DOM.importIntoDoc(this.element);
|
||||
var elementsWithBindingsDynamic;
|
||||
if (this.isTemplateElement) {
|
||||
@ -362,9 +368,11 @@ export class ProtoView {
|
||||
if (isPresent(protoElementInjector)) {
|
||||
if (isPresent(protoElementInjector.parent)) {
|
||||
var parentElementInjector = elementInjectors[protoElementInjector.parent.index];
|
||||
elementInjector = protoElementInjector.instantiate(parentElementInjector, null, binder.events);
|
||||
elementInjector = protoElementInjector.instantiate(parentElementInjector, null,
|
||||
binder.events, reflector);
|
||||
} else {
|
||||
elementInjector = protoElementInjector.instantiate(null, hostElementInjector, binder.events);
|
||||
elementInjector = protoElementInjector.instantiate(null, hostElementInjector,
|
||||
binder.events, reflector);
|
||||
ListWrapper.push(rootElementInjectors, elementInjector);
|
||||
}
|
||||
}
|
||||
@ -391,7 +399,7 @@ export class ProtoView {
|
||||
var bindingPropagationConfig = null;
|
||||
if (isPresent(binder.componentDirective)) {
|
||||
var strategy = this.shadowDomStrategy;
|
||||
var childView = binder.nestedProtoView.instantiate(elementInjector, eventManager);
|
||||
var childView = binder.nestedProtoView.instantiate(elementInjector, eventManager, reflector);
|
||||
view.changeDetector.addChild(childView.changeDetector);
|
||||
|
||||
lightDom = strategy.constructLightDom(view, childView, element);
|
||||
@ -407,7 +415,7 @@ export class ProtoView {
|
||||
if (isPresent(binder.viewportDirective)) {
|
||||
var destLightDom = this._directParentElementLightDom(protoElementInjector, preBuiltObjects);
|
||||
viewContainer = new ViewContainer(view, element, binder.nestedProtoView, elementInjector,
|
||||
eventManager, destLightDom);
|
||||
eventManager, reflector, destLightDom);
|
||||
ListWrapper.push(viewContainers, viewContainer);
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import {Injector} from 'angular2/di';
|
||||
import * as eiModule from 'angular2/src/core/compiler/element_injector';
|
||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {EventManager} from 'angular2/src/core/events/event_manager';
|
||||
import {Reflector} from 'angular2/src/reflection/reflection';
|
||||
|
||||
export class ViewContainer {
|
||||
parentView: viewModule.View;
|
||||
@ -14,17 +15,24 @@ export class ViewContainer {
|
||||
_views: List<viewModule.View>;
|
||||
_lightDom: any;
|
||||
_eventManager: EventManager;
|
||||
_reflector: Reflector;
|
||||
elementInjector: eiModule.ElementInjector;
|
||||
appInjector: Injector;
|
||||
hostElementInjector: eiModule.ElementInjector;
|
||||
|
||||
constructor(parentView: viewModule.View, templateElement, defaultProtoView: viewModule.ProtoView,
|
||||
elementInjector: eiModule.ElementInjector, eventManager: EventManager, lightDom = null) {
|
||||
constructor(parentView: viewModule.View,
|
||||
templateElement,
|
||||
defaultProtoView: viewModule.ProtoView,
|
||||
elementInjector: eiModule.ElementInjector,
|
||||
eventManager: EventManager,
|
||||
reflector: Reflector,
|
||||
lightDom = null) {
|
||||
this.parentView = parentView;
|
||||
this.templateElement = templateElement;
|
||||
this.defaultProtoView = defaultProtoView;
|
||||
this.elementInjector = elementInjector;
|
||||
this._lightDom = lightDom;
|
||||
this._reflector = reflector;
|
||||
|
||||
// The order in this list matches the DOM order.
|
||||
this._views = [];
|
||||
@ -73,7 +81,8 @@ export class ViewContainer {
|
||||
if (!this.hydrated()) throw new BaseException(
|
||||
'Cannot create views on a dehydrated ViewContainer');
|
||||
// TODO(rado): replace with viewFactory.
|
||||
var newView = this.defaultProtoView.instantiate(this.hostElementInjector, this._eventManager);
|
||||
var newView = this.defaultProtoView.instantiate(this.hostElementInjector, this._eventManager,
|
||||
this._reflector);
|
||||
// insertion must come before hydration so that element injector trees are attached.
|
||||
this.insert(newView, atIndex);
|
||||
newView.hydrate(this.appInjector, this.hostElementInjector, this.parentView.context);
|
||||
|
Reference in New Issue
Block a user