feat(di): removed app injector

BREAKING CHANGE:

THe appInjector property has been removed. Instead use viewInjector or hostInjector.
This commit is contained in:
vsavkin
2015-06-29 11:15:49 -07:00
parent 73a939e76c
commit f0e962c55e
36 changed files with 463 additions and 566 deletions

View File

@ -822,8 +822,7 @@ export interface DirectiveArgs {
* When a component is instantiated, Angular
* - creates a shadow DOM for the component.
* - loads the selected template into the shadow DOM.
* - creates a child {@link Injector} which is configured with the `appInjector` for the
* {@link Component}.
* - creates all the injectable objects configured with `hostInjector` and `viewInjector`.
*
* All template expressions and statements are then evaluated against the component instance.
*
@ -865,59 +864,6 @@ export class Component extends Directive {
*/
changeDetection: string;
/**
* Defines the set of injectable objects that are visible to a Component and its children.
*
* The `appInjector` defined in the Component annotation allow you to configure a set of bindings
* for the component's
* injector.
*
* When a component is instantiated, Angular creates a new child Injector, which is configured
* with the bindings in
* the Component `appInjector` annotation. The injectable objects then become available for
* injection to the component
* itself and any of the directives in the component's template, i.e. they are not available to
* the directives which
* are children in the component's light DOM.
*
*
* The syntax for configuring the `appInjector` injectable is identical to {@link Injector}
* injectable configuration.
* See {@link Injector} for additional detail.
*
*
* ## Simple Example
*
* Here is an example of a class that can be injected:
*
* ```
* class Greeter {
* greet(name:string) {
* return 'Hello ' + name + '!';
* }
* }
*
* @Component({
* selector: 'greet',
* appInjector: [
* Greeter
* ]
* })
* @View({
* template: `{{greeter.greet('world')}}!`,
* directives: [Child]
* })
* class HelloWorld {
* greeter:Greeter;
*
* constructor(greeter:Greeter) {
* this.greeter = greeter;
* }
* }
* ```
*/
appInjector: List<any>;
/**
* Defines the set of injectable objects that are visible to its view dom children.
*
@ -960,9 +906,8 @@ export class Component extends Directive {
*/
viewInjector: List<any>;
constructor({selector, properties, events, host, exportAs, appInjector, lifecycle, hostInjector,
viewInjector, changeDetection = DEFAULT,
compileChildren = true}: ComponentArgs = {}) {
constructor({selector, properties, events, host, exportAs, lifecycle, hostInjector, viewInjector,
changeDetection = DEFAULT, compileChildren = true}: ComponentArgs = {}) {
super({
selector: selector,
properties: properties,
@ -975,13 +920,11 @@ export class Component extends Directive {
});
this.changeDetection = changeDetection;
this.appInjector = appInjector;
this.viewInjector = viewInjector;
}
}
export interface ComponentArgs extends DirectiveArgs {
appInjector?: List<any>;
viewInjector?: List<any>;
changeDetection?: string;
}

View File

@ -209,11 +209,9 @@ function _createNgZone(givenReporter: Function): NgZone {
* 1. It uses the component's `selector` property to locate the DOM element which needs to be
* upgraded into
* the angular component.
* 2. It creates a new child injector (from the platform injector) and configures the injector with
* the component's
* `appInjector`. Optionally, you can also override the injector configuration for an app by
* invoking
* `bootstrap` with the `componentInjectableBindings` argument.
* 2. It creates a new child injector (from the platform injector). Optionally, you can also
* override the injector configuration for an app by
* invoking `bootstrap` with the `componentInjectableBindings` argument.
* 3. It creates a new `Zone` and connects it to the angular application's change detection domain
* instance.
* 4. It creates a shadow DOM on the selected component's host element and loads the template into
@ -270,9 +268,9 @@ function _createNgZone(givenReporter: Function): NgZone {
* - `appComponentType`: The root component which should act as the application. This is a reference
* to a `Type`
* which is annotated with `@Component(...)`.
* - `componentInjectableBindings`: An additional set of bindings that can be added to `appInjector`
* for the
* {@link Component} to override default injection behavior.
* - `componentInjectableBindings`: An additional set of bindings that can be added to the app
* injector
* to override default injection behavior.
* - `errorReporter`: `function(exception:any, stackTrace:string)` a default error reporter for
* unhandled exceptions.
*

View File

@ -30,8 +30,8 @@ export class DynamicComponentLoader {
* component's selector.
* The loaded component receives injection normally as a hosted view.
*/
loadAsRoot(typeOrBinding: Type | Binding, overrideSelector: string = null,
injector: Injector = null): Promise<ComponentRef> {
loadAsRoot(typeOrBinding: Type | Binding, overrideSelector: string,
injector: Injector): Promise<ComponentRef> {
return this._compiler.compileInHost(typeOrBinding)
.then(hostProtoViewRef => {
var hostViewRef =
@ -51,10 +51,10 @@ export class DynamicComponentLoader {
* injection normally as a hosted view.
*/
loadIntoLocation(typeOrBinding: Type | Binding, hostLocation: ElementRef, anchorName: string,
injector: Injector = null): Promise<ComponentRef> {
bindings: ResolvedBinding[] = null): Promise<ComponentRef> {
return this.loadNextToLocation(
typeOrBinding, this._viewManager.getNamedElementInComponentView(hostLocation, anchorName),
injector);
bindings);
}
/**
@ -62,12 +62,12 @@ export class DynamicComponentLoader {
* injection normally as a hosted view.
*/
loadNextToLocation(typeOrBinding: Type | Binding, location: ElementRef,
injector: Injector = null): Promise<ComponentRef> {
bindings: ResolvedBinding[] = null): Promise<ComponentRef> {
return this._compiler.compileInHost(typeOrBinding)
.then(hostProtoViewRef => {
var viewContainer = this._viewManager.getViewContainer(location);
var hostViewRef =
viewContainer.create(hostProtoViewRef, viewContainer.length, null, injector);
viewContainer.create(hostProtoViewRef, viewContainer.length, null, bindings);
var newLocation = this._viewManager.getHostElement(hostViewRef);
var component = this._viewManager.getComponent(newLocation);

View File

@ -16,8 +16,6 @@ import {
PUBLIC,
PRIVATE,
undefinedValue,
InjectorInlineStrategy,
InjectorDynamicStrategy,
Key,
Dependency,
bind,
@ -32,6 +30,11 @@ import {
VisibilityAnnotation,
self
} from 'angular2/di';
import {
InjectorInlineStrategy,
InjectorDynamicStrategy,
BindingWithVisibility
} from 'angular2/src/di/injector';
import {Attribute, Query} from 'angular2/src/core/annotations_impl/di';
@ -201,7 +204,6 @@ export class DirectiveDependency extends Dependency {
export class DirectiveBinding extends ResolvedBinding {
constructor(key: Key, factory: Function, dependencies: List<Dependency>,
public resolvedAppInjectables: List<ResolvedBinding>,
public resolvedHostInjectables: List<ResolvedBinding>,
public resolvedViewInjectables: List<ResolvedBinding>,
public metadata: DirectiveMetadata) {
@ -235,9 +237,6 @@ export class DirectiveBinding extends ResolvedBinding {
var rb = binding.resolve();
var deps = ListWrapper.map(rb.dependencies, DirectiveDependency.createFrom);
var resolvedAppInjectables = ann instanceof Component && isPresent(ann.appInjector) ?
Injector.resolve(ann.appInjector) :
[];
var resolvedHostInjectables =
isPresent(ann.hostInjector) ? resolveBindings(ann.hostInjector) : [];
var resolvedViewInjectables = ann instanceof Component && isPresent(ann.viewInjector) ?
@ -265,8 +264,8 @@ export class DirectiveBinding extends ResolvedBinding {
exportAs: ann.exportAs
});
return new DirectiveBinding(rb.key, rb.factory, deps, resolvedAppInjectables,
resolvedHostInjectables, resolvedViewInjectables, metadata);
return new DirectiveBinding(rb.key, rb.factory, deps, resolvedHostInjectables,
resolvedViewInjectables, metadata);
}
static _readAttributes(deps) {
@ -313,39 +312,35 @@ export class HostActionAccessor {
}
}
export class BindingData {
constructor(public binding: ResolvedBinding, public visibility: number) {}
function _createEventEmitterAccessors(bwv: BindingWithVisibility): EventEmitterAccessor[] {
var binding = bwv.binding;
if (!(binding instanceof DirectiveBinding)) return [];
var db = <DirectiveBinding>binding;
return ListWrapper.map(db.eventEmitters, eventConfig => {
let fieldName;
let eventName;
var colonIdx = eventConfig.indexOf(':');
if (colonIdx > -1) {
// long format: 'fieldName: eventName'
fieldName = StringWrapper.substring(eventConfig, 0, colonIdx).trim();
eventName = StringWrapper.substring(eventConfig, colonIdx + 1).trim();
} else {
// short format: 'name' when fieldName and eventName are the same
fieldName = eventName = eventConfig;
}
return new EventEmitterAccessor(eventName, reflector.getter(fieldName));
});
}
getKeyId(): number { return this.binding.key.id; }
createEventEmitterAccessors(): List<EventEmitterAccessor> {
if (!(this.binding instanceof DirectiveBinding)) return [];
var db = <DirectiveBinding>this.binding;
return ListWrapper.map(db.eventEmitters, eventConfig => {
let fieldName;
let eventName;
var colonIdx = eventConfig.indexOf(':');
if (colonIdx > -1) {
// long format: 'fieldName: eventName'
fieldName = StringWrapper.substring(eventConfig, 0, colonIdx).trim();
eventName = StringWrapper.substring(eventConfig, colonIdx + 1).trim();
} else {
// short format: 'name' when fieldName and eventName are the same
fieldName = eventName = eventConfig;
}
return new EventEmitterAccessor(eventName, reflector.getter(fieldName));
});
}
createHostActionAccessors(): HostActionAccessor[] {
if (!(this.binding instanceof DirectiveBinding)) return [];
var res = [];
var db = <DirectiveBinding>this.binding;
MapWrapper.forEach(db.hostActions, (actionExpression, actionName) => {
res.push(new HostActionAccessor(actionExpression, reflector.getter(actionName)));
});
return res;
}
function _createHostActionAccessors(bwv: BindingWithVisibility): HostActionAccessor[] {
var binding = bwv.binding;
if (!(binding instanceof DirectiveBinding)) return [];
var res = [];
var db = <DirectiveBinding>binding;
MapWrapper.forEach(db.hostActions, (actionExpression, actionName) => {
res.push(new HostActionAccessor(actionExpression, reflector.getter(actionName)));
});
return res;
}
export class ProtoElementInjector {
@ -360,62 +355,65 @@ export class ProtoElementInjector {
directiveVariableBindings: Map<string, number>): ProtoElementInjector {
var bd = [];
ProtoElementInjector._createDirectiveBindingData(bindings, bd, firstBindingIsComponent);
ProtoElementInjector._createDirectiveBindingWithVisibility(bindings, bd,
firstBindingIsComponent);
if (firstBindingIsComponent) {
ProtoElementInjector._createViewInjectorBindingData(bindings, bd);
ProtoElementInjector._createViewInjectorBindingWithVisibility(bindings, bd);
}
ProtoElementInjector._createHostInjectorBindingData(bindings, bd, firstBindingIsComponent);
ProtoElementInjector._createHostInjectorBindingWithVisibility(bindings, bd,
firstBindingIsComponent);
return new ProtoElementInjector(parent, index, bd, distanceToParent, firstBindingIsComponent,
directiveVariableBindings);
}
private static _createDirectiveBindingData(dirBindings: List<ResolvedBinding>,
bd: List<BindingData>,
firstBindingIsComponent: boolean) {
private static _createDirectiveBindingWithVisibility(dirBindings: List<ResolvedBinding>,
bd: BindingWithVisibility[],
firstBindingIsComponent: boolean) {
ListWrapper.forEach(dirBindings, dirBinding => {
bd.push(ProtoElementInjector._createBindingData(firstBindingIsComponent, dirBinding,
dirBindings, dirBinding));
bd.push(ProtoElementInjector._createBindingWithVisibility(firstBindingIsComponent, dirBinding,
dirBindings, dirBinding));
});
}
private static _createHostInjectorBindingData(dirBindings: List<ResolvedBinding>,
bd: List<BindingData>,
firstBindingIsComponent: boolean) {
private static _createHostInjectorBindingWithVisibility(dirBindings: List<ResolvedBinding>,
bd: BindingWithVisibility[],
firstBindingIsComponent: boolean) {
ListWrapper.forEach(dirBindings, dirBinding => {
ListWrapper.forEach(dirBinding.resolvedHostInjectables, b => {
bd.push(ProtoElementInjector._createBindingData(firstBindingIsComponent, dirBinding,
dirBindings, b));
bd.push(ProtoElementInjector._createBindingWithVisibility(firstBindingIsComponent,
dirBinding, dirBindings, b));
});
});
}
private static _createBindingData(firstBindingIsComponent, dirBinding, dirBindings, binding) {
private static _createBindingWithVisibility(firstBindingIsComponent, dirBinding, dirBindings,
binding) {
var isComponent = firstBindingIsComponent && dirBindings[0] === dirBinding;
return new BindingData(binding, isComponent ? PUBLIC_AND_PRIVATE : PUBLIC);
return new BindingWithVisibility(binding, isComponent ? PUBLIC_AND_PRIVATE : PUBLIC);
}
private static _createViewInjectorBindingData(bindings: List<ResolvedBinding>,
bd: List<BindingData>) {
private static _createViewInjectorBindingWithVisibility(bindings: List<ResolvedBinding>,
bd: BindingWithVisibility[]) {
var db = <DirectiveBinding>bindings[0];
ListWrapper.forEach(db.resolvedViewInjectables, b => bd.push(new BindingData(b, PRIVATE)));
ListWrapper.forEach(db.resolvedViewInjectables,
b => bd.push(new BindingWithVisibility(b, PRIVATE)));
}
constructor(public parent: ProtoElementInjector, public index: int, bd: List<BindingData>,
constructor(public parent: ProtoElementInjector, public index: int, bwv: BindingWithVisibility[],
public distanceToParent: number, public _firstBindingIsComponent: boolean,
public directiveVariableBindings: Map<string, number>) {
var length = bd.length;
var length = bwv.length;
this.protoInjector =
new ProtoInjector(isPresent(parent) ? parent.protoInjector : null, bd, distanceToParent);
this.protoInjector = new ProtoInjector(bwv, distanceToParent);
this.eventEmitterAccessors = ListWrapper.createFixedSize(length);
this.hostActionAccessors = ListWrapper.createFixedSize(length);
for (var i = 0; i < length; ++i) {
this.eventEmitterAccessors[i] = bd[i].createEventEmitterAccessors();
this.hostActionAccessors[i] = bd[i].createHostActionAccessors();
this.eventEmitterAccessors[i] = _createEventEmitterAccessors(bwv[i]);
this.hostActionAccessors[i] = _createHostActionAccessors(bwv[i]);
}
}
@ -432,10 +430,7 @@ export class ProtoElementInjector {
export class ElementInjector extends TreeNode<ElementInjector> {
private _lightDomAppInjector: Injector = null;
private _shadowDomAppInjector: Injector = null;
private _host: ElementInjector;
private _preBuiltObjects = null;
// Queries are added during construction or linking with a new parent.
@ -453,9 +448,10 @@ export class ElementInjector extends TreeNode<ElementInjector> {
super(parent);
this._injector = new Injector(this._proto.protoInjector);
this._injector.ei = this; // TODO savkin remove after mergin DI and EI
// we couple ourselves to the injector strategy to avoid polymoprhic calls
var injectorStrategy = <any>this._injector.strategy;
var injectorStrategy = <any>this._injector.internalStrategy;
this._strategy = injectorStrategy instanceof InjectorInlineStrategy ?
new ElementInjectorInlineStrategy(
injectorStrategy, this) :
@ -472,10 +468,8 @@ export class ElementInjector extends TreeNode<ElementInjector> {
this.hydrated = false;
this._host = null;
this._preBuiltObjects = null;
this._lightDomAppInjector = null;
this._shadowDomAppInjector = null;
this._strategy.callOnDestroy();
this._injector.dehydrate();
this._injector.internalStrategy.dehydrate();
}
onAllChangesDone(): void {
@ -490,24 +484,12 @@ export class ElementInjector extends TreeNode<ElementInjector> {
}
}
hydrate(injector: Injector, host: ElementInjector, preBuiltObjects: PreBuiltObjects): void {
var p = this._proto;
hydrate(imperativelyCreatedInjector: Injector, host: ElementInjector,
preBuiltObjects: PreBuiltObjects): void {
this._host = host;
this._lightDomAppInjector = injector;
this._preBuiltObjects = preBuiltObjects;
if (p._firstBindingIsComponent) {
this._shadowDomAppInjector =
this._createShadowDomAppInjector(this._strategy.getComponentBinding(), injector);
}
this._checkShadowDomAppInjector(this._shadowDomAppInjector);
var parentInjector = isPresent(this._parent) ? this._parent._injector : null;
var hostInjector = isPresent(host) ? host._injector : null;
this._injector.hydrate(parentInjector, hostInjector, this);
this._hydrateInjector(imperativelyCreatedInjector, host);
this._addDirectivesToQueries();
this._addVarBindingsToQueries();
@ -515,6 +497,59 @@ export class ElementInjector extends TreeNode<ElementInjector> {
this.hydrated = true;
}
private _hydrateInjector(imperativelyCreatedInjector: Injector, host: ElementInjector): void {
if (isPresent(this._parent)) {
this._reattachInjector(this._injector, this._parent._injector, false);
} else {
// This injector is at the boundary.
//
// The injector tree we are assembling:
//
// host._injector (only if present)
// |
// |boundary
// |
// imperativelyCreatedInjector (only if present)
// |
// |boundary
// |
// this._injector
//
// host._injector (only if present)
// |
// |boundary
// |
// imperativelyCreatedInjector (only if present)
if (isPresent(imperativelyCreatedInjector) && isPresent(host)) {
this._reattachInjector(imperativelyCreatedInjector, host._injector, true);
}
// host._injector OR imperativelyCreatedInjector OR null
// |
// |boundary
// |
// this._injector
var parent = this._getParentInjector(imperativelyCreatedInjector, host);
this._reattachInjector(this._injector, parent, true);
}
}
private _getParentInjector(injector: Injector, host: ElementInjector): Injector {
if (isPresent(injector)) {
return injector;
} else if (isPresent(host)) {
return host._injector;
} else {
return null;
}
}
private _reattachInjector(injector: Injector, parentInjector: Injector, isBoundary: boolean) {
injector.internalStrategy.attach(parentInjector, isBoundary);
injector.internalStrategy.hydrate();
}
hasVariableBinding(name: string): boolean {
var vb = this._proto.directiveVariableBindings;
return isPresent(vb) && vb.has(name);
@ -525,25 +560,6 @@ export class ElementInjector extends TreeNode<ElementInjector> {
return isPresent(index) ? this.getDirectiveAtIndex(<number>index) : this.getElementRef();
}
private _createShadowDomAppInjector(componentDirective: DirectiveBinding,
appInjector: Injector): Injector {
if (!ListWrapper.isEmpty(componentDirective.resolvedAppInjectables)) {
return appInjector.createChildFromResolved(componentDirective.resolvedAppInjectables);
} else {
return appInjector;
}
}
private _checkShadowDomAppInjector(shadowDomAppInjector: Injector): void {
if (this._proto._firstBindingIsComponent && isBlank(shadowDomAppInjector)) {
throw new BaseException(
'A shadowDomAppInjector is required as this ElementInjector contains a component');
} else if (!this._proto._firstBindingIsComponent && isPresent(shadowDomAppInjector)) {
throw new BaseException(
'No shadowDomAppInjector allowed as there is not component stored in this ElementInjector');
}
}
get(token): any { return this._injector.get(token); }
hasDirective(type: Type): boolean { return isPresent(this._injector.getOptional(type)); }
@ -573,7 +589,7 @@ export class ElementInjector extends TreeNode<ElementInjector> {
isComponentKey(key: Key): boolean { return this._strategy.isComponentKey(key); }
getDependency(dep: any): any {
var key = dep.key;
var key: Key = dep.key;
if (!(dep instanceof DirectiveDependency)) return undefinedValue;
@ -802,22 +818,10 @@ export class ElementInjector extends TreeNode<ElementInjector> {
if (this._query2 == query) this._query2 = null;
}
appInjector(requestor: Key): Injector {
if (isPresent(requestor) && this.isComponentKey(requestor)) {
return this._shadowDomAppInjector;
} else {
return this._lightDomAppInjector;
}
}
getDirectiveAtIndex(index: number): any { return this._injector.getObjAtIndex(index); }
getDirectiveAtIndex(index: number): any { return this._injector.getAt(index); }
hasInstances(): boolean { return this._proto.hasBindings && this.hydrated; }
getLightDomAppInjector(): Injector { return this._lightDomAppInjector; }
getShadowDomAppInjector(): Injector { return this._shadowDomAppInjector; }
getHost(): ElementInjector { return this._host; }
getBoundElementIndex(): number { return this._proto.index; }

View File

@ -348,7 +348,7 @@ function _findParentProtoElementInjectorWithDistance(
}
}
} while (binderIndex !== -1);
return new ParentProtoElementInjectorWithDistance(null, -1);
return new ParentProtoElementInjectorWithDistance(null, 0);
}
function _createProtoElementInjector(binderIndex, parentPeiWithDistance, renderElementBinder,

View File

@ -1,5 +1,5 @@
import {ListWrapper, List} from 'angular2/src/facade/collection';
import {Injector} from 'angular2/di';
import {ResolvedBinding} from 'angular2/di';
import {isPresent, isBlank} from 'angular2/src/facade/lang';
import * as avmModule from './view_manager';
@ -31,10 +31,10 @@ export class ViewContainerRef {
// TODO(rado): profile and decide whether bounds checks should be added
// to the methods below.
create(protoViewRef: ProtoViewRef = null, atIndex: number = -1, context: ElementRef = null,
injector: Injector = null): ViewRef {
bindings: ResolvedBinding[] = null): ViewRef {
if (atIndex == -1) atIndex = this.length;
return this.viewManager.createViewInContainer(this.element, atIndex, protoViewRef, context,
injector);
bindings);
}
insert(viewRef: ViewRef, atIndex: number = -1): ViewRef {

View File

@ -1,4 +1,4 @@
import {Injector, Binding, Injectable} from 'angular2/di';
import {Injector, Binding, Injectable, ResolvedBinding} from 'angular2/di';
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
import * as viewModule from './view';
import {ElementRef} from './element_ref';
@ -73,6 +73,7 @@ export class AppViewManager {
this._utils.hydrateRootHostView(hostView, injector);
this._viewHydrateRecurse(hostView);
return hostView.ref;
}
@ -89,7 +90,7 @@ export class AppViewManager {
createViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
protoViewRef: ProtoViewRef, context: ElementRef = null,
injector: Injector = null): ViewRef {
bindings: ResolvedBinding[] = null): ViewRef {
var protoView = internalProtoView(protoViewRef);
var parentView = internalView(viewContainerLocation.parentView);
var boundElementIndex = viewContainerLocation.boundElementIndex;
@ -106,7 +107,7 @@ export class AppViewManager {
this._utils.attachViewInContainer(parentView, boundElementIndex, contextView,
contextBoundElementIndex, atIndex, view);
this._utils.hydrateViewInContainer(parentView, boundElementIndex, contextView,
contextBoundElementIndex, atIndex, injector);
contextBoundElementIndex, atIndex, bindings);
this._viewHydrateRecurse(view);
return view.ref;
}

View File

@ -1,4 +1,4 @@
import {Injector, Binding, Injectable} from 'angular2/di';
import {Injector, Binding, Injectable, ResolvedBinding} 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';
@ -74,15 +74,14 @@ export class AppViewManagerUtils {
hostView.componentChildViews[boundElementIndex] = null;
}
hydrateComponentView(hostView: viewModule.AppView, boundElementIndex: number,
injector: Injector = null) {
hydrateComponentView(hostView: viewModule.AppView, boundElementIndex: number) {
var elementInjector = hostView.elementInjectors[boundElementIndex];
var componentView = hostView.componentChildViews[boundElementIndex];
var component = this.getComponentInstance(hostView, boundElementIndex);
this._hydrateView(componentView, injector, elementInjector, component, null);
this._hydrateView(componentView, null, elementInjector, component, null);
}
hydrateRootHostView(hostView: viewModule.AppView, injector: Injector = null) {
hydrateRootHostView(hostView: viewModule.AppView, injector: Injector) {
this._hydrateView(hostView, injector, null, new Object(), null);
}
@ -132,7 +131,7 @@ export class AppViewManagerUtils {
hydrateViewInContainer(parentView: viewModule.AppView, boundElementIndex: number,
contextView: viewModule.AppView, contextBoundElementIndex: number,
atIndex: number, injector: Injector) {
atIndex: number, bindings: ResolvedBinding[]) {
if (isBlank(contextView)) {
contextView = parentView;
contextBoundElementIndex = boundElementIndex;
@ -140,21 +139,15 @@ export class AppViewManagerUtils {
var viewContainer = parentView.viewContainers[boundElementIndex];
var view = viewContainer.views[atIndex];
var elementInjector = contextView.elementInjectors[contextBoundElementIndex];
if (isBlank(elementInjector.getHost()) && isBlank(injector)) {
injector = elementInjector.getShadowDomAppInjector();
}
var injector = isPresent(bindings) ? Injector.fromResolvedBindings(bindings) : null;
this._hydrateView(view, injector, elementInjector.getHost(), contextView.context,
contextView.locals);
}
_hydrateView(view: viewModule.AppView, appInjector: Injector,
_hydrateView(view: viewModule.AppView, injector: Injector,
hostElementInjector: eli.ElementInjector, context: Object, parentLocals: Locals) {
if (isBlank(appInjector)) {
appInjector = hostElementInjector.getShadowDomAppInjector();
}
if (isBlank(appInjector)) {
appInjector = hostElementInjector.getLightDomAppInjector();
}
view.context = context;
view.locals.parent = parentLocals;
@ -163,7 +156,7 @@ export class AppViewManagerUtils {
var elementInjector = view.elementInjectors[i];
if (isPresent(elementInjector)) {
elementInjector.hydrate(appInjector, hostElementInjector, view.preBuiltObjects[i]);
elementInjector.hydrate(injector, hostElementInjector, view.preBuiltObjects[i]);
this._populateViewLocals(view, elementInjector);
this._setUpEventEmitters(view, elementInjector, i);
this._setUpHostActions(view, elementInjector, i);

View File

@ -15,7 +15,7 @@ import {DOM} from 'angular2/src/dom/dom_adapter';
* ```javascript
* @Component({
* selector: 'my-app',
* appInjector: [
* viewInjector: [
* bind(ExceptionHandler).toClass(MyExceptionHandler)
* ]
* })

View File

@ -97,16 +97,14 @@ export class Injectable {
* @exportedAs angular2/di_annotations
*/
@CONST()
export class Visibility extends DependencyAnnotation {
constructor(public depth: number, public crossComponentBoundaries: boolean,
public _includeSelf: boolean) {
super();
export class Visibility {
constructor(public depth: number, public crossBoundaries: boolean, public _includeSelf: boolean) {
}
get includeSelf(): boolean { return isBlank(this._includeSelf) ? false : this._includeSelf; }
toString(): string {
return `@Visibility(depth: ${this.depth}, crossComponentBoundaries: ${this.crossComponentBoundaries}, includeSelf: ${this.includeSelf}})`;
return `@Visibility(depth: ${this.depth}, crossBoundaries: ${this.crossBoundaries}, includeSelf: ${this.includeSelf}})`;
}
}

View File

@ -1,7 +1,7 @@
/// <reference path="../../typings/es6-promise/es6-promise.d.ts" />
import {Map, List, MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {ResolvedBinding, Binding, BindingBuilder, bind} from './binding';
import {ResolvedBinding, Binding, Dependency, BindingBuilder, bind} from './binding';
import {
AbstractBindingError,
NoBindingError,
@ -14,7 +14,7 @@ import {
import {FunctionWrapper, Type, isPresent, isBlank, CONST_EXPR} from 'angular2/src/facade/lang';
import {Key} from './key';
import {resolveForwardRef} from './forward_ref';
import {self, unbounded} from './annotations_impl';
import {Visibility, unbounded} from './annotations_impl';
const _constructing = CONST_EXPR(new Object());
const _notFound = CONST_EXPR(new Object());
@ -67,58 +67,58 @@ export class ProtoInjectorInlineStrategy implements ProtoInjectorStrategy {
visibility8: number = null;
visibility9: number = null;
constructor(protoEI: ProtoInjector, bd: any[]) {
var length = bd.length;
constructor(protoEI: ProtoInjector, bwv: BindingWithVisibility[]) {
var length = bwv.length;
if (length > 0) {
this.binding0 = bd[0].binding;
this.keyId0 = bd[0].getKeyId();
this.visibility0 = bd[0].visibility;
this.binding0 = bwv[0].binding;
this.keyId0 = bwv[0].getKeyId();
this.visibility0 = bwv[0].visibility;
}
if (length > 1) {
this.binding1 = bd[1].binding;
this.keyId1 = bd[1].getKeyId();
this.visibility1 = bd[1].visibility;
this.binding1 = bwv[1].binding;
this.keyId1 = bwv[1].getKeyId();
this.visibility1 = bwv[1].visibility;
}
if (length > 2) {
this.binding2 = bd[2].binding;
this.keyId2 = bd[2].getKeyId();
this.visibility2 = bd[2].visibility;
this.binding2 = bwv[2].binding;
this.keyId2 = bwv[2].getKeyId();
this.visibility2 = bwv[2].visibility;
}
if (length > 3) {
this.binding3 = bd[3].binding;
this.keyId3 = bd[3].getKeyId();
this.visibility3 = bd[3].visibility;
this.binding3 = bwv[3].binding;
this.keyId3 = bwv[3].getKeyId();
this.visibility3 = bwv[3].visibility;
}
if (length > 4) {
this.binding4 = bd[4].binding;
this.keyId4 = bd[4].getKeyId();
this.visibility4 = bd[4].visibility;
this.binding4 = bwv[4].binding;
this.keyId4 = bwv[4].getKeyId();
this.visibility4 = bwv[4].visibility;
}
if (length > 5) {
this.binding5 = bd[5].binding;
this.keyId5 = bd[5].getKeyId();
this.visibility5 = bd[5].visibility;
this.binding5 = bwv[5].binding;
this.keyId5 = bwv[5].getKeyId();
this.visibility5 = bwv[5].visibility;
}
if (length > 6) {
this.binding6 = bd[6].binding;
this.keyId6 = bd[6].getKeyId();
this.visibility6 = bd[6].visibility;
this.binding6 = bwv[6].binding;
this.keyId6 = bwv[6].getKeyId();
this.visibility6 = bwv[6].visibility;
}
if (length > 7) {
this.binding7 = bd[7].binding;
this.keyId7 = bd[7].getKeyId();
this.visibility7 = bd[7].visibility;
this.binding7 = bwv[7].binding;
this.keyId7 = bwv[7].getKeyId();
this.visibility7 = bwv[7].visibility;
}
if (length > 8) {
this.binding8 = bd[8].binding;
this.keyId8 = bd[8].getKeyId();
this.visibility8 = bd[8].visibility;
this.binding8 = bwv[8].binding;
this.keyId8 = bwv[8].getKeyId();
this.visibility8 = bwv[8].visibility;
}
if (length > 9) {
this.binding9 = bd[9].binding;
this.keyId9 = bd[9].getKeyId();
this.visibility9 = bd[9].visibility;
this.binding9 = bwv[9].binding;
this.keyId9 = bwv[9].getKeyId();
this.visibility9 = bwv[9].visibility;
}
}
@ -146,17 +146,17 @@ export class ProtoInjectorDynamicStrategy implements ProtoInjectorStrategy {
keyIds: number[];
visibilities: number[];
constructor(protoInj: ProtoInjector, bd: any[]) {
var len = bd.length;
constructor(protoInj: ProtoInjector, bwv: BindingWithVisibility[]) {
var len = bwv.length;
this.bindings = ListWrapper.createFixedSize(len);
this.keyIds = ListWrapper.createFixedSize(len);
this.visibilities = ListWrapper.createFixedSize(len);
for (var i = 0; i < len; i++) {
this.bindings[i] = bd[i].binding;
this.keyIds[i] = bd[i].getKeyId();
this.visibilities[i] = bd[i].visibility;
this.bindings[i] = bwv[i].binding;
this.keyIds[i] = bwv[i].getKeyId();
this.visibilities[i] = bwv[i].visibility;
}
}
@ -175,10 +175,10 @@ export class ProtoInjectorDynamicStrategy implements ProtoInjectorStrategy {
export class ProtoInjector {
_strategy: ProtoInjectorStrategy;
constructor(public parent: ProtoInjector, rb: any[], public distanceToParent: number) {
this._strategy = rb.length > _MAX_CONSTRUCTION_COUNTER ?
new ProtoInjectorDynamicStrategy(this, rb) :
new ProtoInjectorInlineStrategy(this, rb);
constructor(bwv: BindingWithVisibility[], public distanceToParent: number) {
this._strategy = bwv.length > _MAX_CONSTRUCTION_COUNTER ?
new ProtoInjectorDynamicStrategy(this, bwv) :
new ProtoInjectorInlineStrategy(this, bwv);
}
getBindingAtIndex(index: number): any { return this._strategy.getBindingAtIndex(index); }
@ -191,6 +191,7 @@ export interface InjectorStrategy {
getObjAtIndex(index: number): any;
getMaxNumberOfObjects(): number;
attach(parent: Injector, isBoundary: boolean): void;
hydrate(): void;
dehydrate(): void;
}
@ -213,16 +214,25 @@ export class InjectorInlineStrategy implements InjectorStrategy {
var p = this.protoStrategy;
var inj = this.injector;
if (isPresent(p.keyId0) && isBlank(this.obj0)) this.obj0 = inj._new(p.binding0);
if (isPresent(p.keyId1) && isBlank(this.obj1)) this.obj1 = inj._new(p.binding1);
if (isPresent(p.keyId2) && isBlank(this.obj2)) this.obj2 = inj._new(p.binding2);
if (isPresent(p.keyId3) && isBlank(this.obj3)) this.obj3 = inj._new(p.binding3);
if (isPresent(p.keyId4) && isBlank(this.obj4)) this.obj4 = inj._new(p.binding4);
if (isPresent(p.keyId5) && isBlank(this.obj5)) this.obj5 = inj._new(p.binding5);
if (isPresent(p.keyId6) && isBlank(this.obj6)) this.obj6 = inj._new(p.binding6);
if (isPresent(p.keyId7) && isBlank(this.obj7)) this.obj7 = inj._new(p.binding7);
if (isPresent(p.keyId8) && isBlank(this.obj8)) this.obj8 = inj._new(p.binding8);
if (isPresent(p.keyId9) && isBlank(this.obj9)) this.obj9 = inj._new(p.binding9);
inj._constructionCounter = 0;
if (isPresent(p.keyId0) && isBlank(this.obj0)) this.obj0 = inj._new(p.binding0, p.visibility0);
if (isPresent(p.keyId1) && isBlank(this.obj1)) this.obj1 = inj._new(p.binding1, p.visibility1);
if (isPresent(p.keyId2) && isBlank(this.obj2)) this.obj2 = inj._new(p.binding2, p.visibility2);
if (isPresent(p.keyId3) && isBlank(this.obj3)) this.obj3 = inj._new(p.binding3, p.visibility3);
if (isPresent(p.keyId4) && isBlank(this.obj4)) this.obj4 = inj._new(p.binding4, p.visibility4);
if (isPresent(p.keyId5) && isBlank(this.obj5)) this.obj5 = inj._new(p.binding5, p.visibility5);
if (isPresent(p.keyId6) && isBlank(this.obj6)) this.obj6 = inj._new(p.binding6, p.visibility6);
if (isPresent(p.keyId7) && isBlank(this.obj7)) this.obj7 = inj._new(p.binding7, p.visibility7);
if (isPresent(p.keyId8) && isBlank(this.obj8)) this.obj8 = inj._new(p.binding8, p.visibility8);
if (isPresent(p.keyId9) && isBlank(this.obj9)) this.obj9 = inj._new(p.binding9, p.visibility9);
}
attach(parent: Injector, isBoundary: boolean): void {
var inj = this.injector;
inj._parent = parent;
inj._isBoundary = isBoundary;
}
dehydrate() {
@ -244,61 +254,61 @@ export class InjectorInlineStrategy implements InjectorStrategy {
if (p.keyId0 === keyId && (p.visibility0 & visibility) > 0) {
if (isBlank(this.obj0)) {
this.obj0 = inj._new(p.binding0);
this.obj0 = inj._new(p.binding0, p.visibility0);
}
return this.obj0;
}
if (p.keyId1 === keyId && (p.visibility1 & visibility) > 0) {
if (isBlank(this.obj1)) {
this.obj1 = inj._new(p.binding1);
this.obj1 = inj._new(p.binding1, p.visibility1);
}
return this.obj1;
}
if (p.keyId2 === keyId && (p.visibility2 & visibility) > 0) {
if (isBlank(this.obj2)) {
this.obj2 = inj._new(p.binding2);
this.obj2 = inj._new(p.binding2, p.visibility2);
}
return this.obj2;
}
if (p.keyId3 === keyId && (p.visibility3 & visibility) > 0) {
if (isBlank(this.obj3)) {
this.obj3 = inj._new(p.binding3);
this.obj3 = inj._new(p.binding3, p.visibility3);
}
return this.obj3;
}
if (p.keyId4 === keyId && (p.visibility4 & visibility) > 0) {
if (isBlank(this.obj4)) {
this.obj4 = inj._new(p.binding4);
this.obj4 = inj._new(p.binding4, p.visibility4);
}
return this.obj4;
}
if (p.keyId5 === keyId && (p.visibility5 & visibility) > 0) {
if (isBlank(this.obj5)) {
this.obj5 = inj._new(p.binding5);
this.obj5 = inj._new(p.binding5, p.visibility5);
}
return this.obj5;
}
if (p.keyId6 === keyId && (p.visibility6 & visibility) > 0) {
if (isBlank(this.obj6)) {
this.obj6 = inj._new(p.binding6);
this.obj6 = inj._new(p.binding6, p.visibility6);
}
return this.obj6;
}
if (p.keyId7 === keyId && (p.visibility7 & visibility) > 0) {
if (isBlank(this.obj7)) {
this.obj7 = inj._new(p.binding7);
this.obj7 = inj._new(p.binding7, p.visibility7);
}
return this.obj7;
}
if (p.keyId8 === keyId && (p.visibility8 & visibility) > 0) {
if (isBlank(this.obj8)) {
this.obj8 = inj._new(p.binding8);
this.obj8 = inj._new(p.binding8, p.visibility8);
}
return this.obj8;
}
if (p.keyId9 === keyId && (p.visibility9 & visibility) > 0) {
if (isBlank(this.obj9)) {
this.obj9 = inj._new(p.binding9);
this.obj9 = inj._new(p.binding9, p.visibility9);
}
return this.obj9;
}
@ -335,11 +345,17 @@ export class InjectorDynamicStrategy implements InjectorStrategy {
var p = this.protoStrategy;
for (var i = 0; i < p.keyIds.length; i++) {
if (isPresent(p.keyIds[i]) && isBlank(this.objs[i])) {
this.objs[i] = this.injector._new(p.bindings[i]);
this.objs[i] = this.injector._new(p.bindings[i], p.visibilities[i]);
}
}
}
attach(parent: Injector, isBoundary: boolean): void {
var inj = this.injector;
inj._parent = parent;
inj._isBoundary = isBoundary;
}
dehydrate(): void { ListWrapper.fill(this.objs, null); }
getObjByKeyId(keyId: number, visibility: number): any {
@ -348,7 +364,7 @@ export class InjectorDynamicStrategy implements InjectorStrategy {
for (var i = 0; i < p.keyIds.length; i++) {
if (p.keyIds[i] === keyId && (p.visibilities[i] & visibility) > 0) {
if (isBlank(this.objs[i])) {
this.objs[i] = this.injector._new(p.bindings[i]);
this.objs[i] = this.injector._new(p.bindings[i], p.visibilities[i]);
}
return this.objs[i];
@ -369,7 +385,7 @@ export class InjectorDynamicStrategy implements InjectorStrategy {
getMaxNumberOfObjects(): number { return this.objs.length; }
}
export class BindingData {
export class BindingWithVisibility {
constructor(public binding: ResolvedBinding, public visibility: number){};
getKeyId(): number { return this.binding.key.id; }
@ -449,15 +465,10 @@ export class Injector {
* @param `bindings` can be a list of `Type`, {@link Binding}, {@link ResolvedBinding}, or a
*recursive list of more
* bindings.
* @param `defaultBindings` Setting to true will auto-create bindings.
*/
static resolveAndCreate(bindings: List<Type | Binding | List<any>>,
{defaultBindings = false}: any = {}): Injector {
static resolveAndCreate(bindings: List<Type | Binding | List<any>>): Injector {
var resolvedBindings = Injector.resolve(bindings);
var bd = resolvedBindings.map(b => new BindingData(b, PUBLIC));
var proto = new ProtoInjector(null, bd, 0);
var inj = new Injector(proto);
return inj;
return Injector.fromResolvedBindings(resolvedBindings);
}
/**
@ -466,48 +477,63 @@ export class Injector {
*
* @param `bindings` A sparse list of {@link ResolvedBinding}s. See `resolve` for the
* {@link Injector}.
* @param `defaultBindings` Setting to true will auto-create bindings.
*/
static fromResolvedBindings(bindings: List<ResolvedBinding>,
{defaultBindings = false}: any = {}): Injector {
var bd = bindings.map(b => new BindingData(b, PUBLIC));
var proto = new ProtoInjector(null, bd, 0);
static fromResolvedBindings(bindings: List<ResolvedBinding>): Injector {
var bd = bindings.map(b => new BindingWithVisibility(b, PUBLIC));
var proto = new ProtoInjector(bd, 0);
var inj = new Injector(proto);
return inj;
}
_strategy: InjectorStrategy;
_parent: Injector;
_host: Injector;
_isBoundary: boolean = false;
_constructionCounter: number = 0;
// TODO vsavkin remove it after DI and EI are merged
private _ei: any;
ei: any;
constructor(public _proto: ProtoInjector) {
constructor(public _proto: ProtoInjector, public _parent: Injector = null) {
this._strategy = _proto._strategy.createInjectorStrategy(this);
}
get(token): any { return this._getByKey(Key.get(token), unbounded, false, null); }
/**
* Retrieves an instance from the injector.
*
* @param `token`: usually the `Type` of an object. (Same as the token used while setting up a
*binding).
* @returns an instance represented by the token. Throws if not found.
*/
get(token): any { return this._getByKey(Key.get(token), unbounded, false, PUBLIC_AND_PRIVATE); }
getOptional(token): any { return this._getByKey(Key.get(token), unbounded, true, null); }
getObjAtIndex(index: number): any { return this._strategy.getObjAtIndex(index); }
get parent(): Injector { return this._parent; }
get strategy() { return this._strategy; }
hydrate(parent: Injector, host: Injector, ei: any) {
this._constructionCounter = 0;
this._parent = parent;
this._host = host;
this._ei = ei;
this._strategy.hydrate();
/**
* Retrieves an instance from the injector.
*
* @param `token`: usually a `Type`. (Same as the token used while setting up a binding).
* @returns an instance represented by the token. Returns `null` if not found.
*/
getOptional(token): any {
return this._getByKey(Key.get(token), unbounded, true, PUBLIC_AND_PRIVATE);
}
dehydrate(): void { this._strategy.dehydrate(); }
/**
* Retrieves an instance from the injector.
*
* @param `index`: index of an instance.
* @returns an instance represented by the index. Throws if not found.
*/
getAt(index: number): any { return this._strategy.getObjAtIndex(index); }
/**
* Direct parent of this injector.
*/
get parent(): Injector { return this._parent; }
/**
* Internal. Do not use.
*
* We return `any` not to export the InjectorStrategy type.
*/
get internalStrategy(): any { return this._strategy; }
/**
* Creates a child injector and loads a new set of bindings into it.
@ -522,11 +548,7 @@ export class Injector {
*/
resolveAndCreateChild(bindings: List<Type | Binding | List<any>>): Injector {
var resovledBindings = Injector.resolve(bindings);
var bd = resovledBindings.map(b => new BindingData(b, PUBLIC));
var proto = new ProtoInjector(this._proto, bd, 1);
var inj = new Injector(proto);
inj._parent = this;
return inj;
return this.createChildFromResolved(resovledBindings);
}
/**
@ -537,14 +559,14 @@ export class Injector {
* @returns a new child {@link Injector}.
*/
createChildFromResolved(bindings: List<ResolvedBinding>): Injector {
var bd = bindings.map(b => new BindingData(b, PUBLIC));
var proto = new ProtoInjector(this._proto, bd, 1);
var bd = bindings.map(b => new BindingWithVisibility(b, PUBLIC));
var proto = new ProtoInjector(bd, 1);
var inj = new Injector(proto);
inj._parent = this;
return inj;
}
_new(binding: ResolvedBinding): any {
_new(binding: ResolvedBinding, visibility: number): any {
if (this._constructionCounter++ > this._strategy.getMaxNumberOfObjects()) {
throw new CyclicDependencyError(binding.key);
}
@ -555,26 +577,26 @@ export class Injector {
var d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16, d17, d18, d19;
try {
d0 = length > 0 ? this._getByDependency(deps[0], binding.key) : null;
d1 = length > 1 ? this._getByDependency(deps[1], binding.key) : null;
d2 = length > 2 ? this._getByDependency(deps[2], binding.key) : null;
d3 = length > 3 ? this._getByDependency(deps[3], binding.key) : null;
d4 = length > 4 ? this._getByDependency(deps[4], binding.key) : null;
d5 = length > 5 ? this._getByDependency(deps[5], binding.key) : null;
d6 = length > 6 ? this._getByDependency(deps[6], binding.key) : null;
d7 = length > 7 ? this._getByDependency(deps[7], binding.key) : null;
d8 = length > 8 ? this._getByDependency(deps[8], binding.key) : null;
d9 = length > 9 ? this._getByDependency(deps[9], binding.key) : null;
d10 = length > 10 ? this._getByDependency(deps[10], binding.key) : null;
d11 = length > 11 ? this._getByDependency(deps[11], binding.key) : null;
d12 = length > 12 ? this._getByDependency(deps[12], binding.key) : null;
d13 = length > 13 ? this._getByDependency(deps[13], binding.key) : null;
d14 = length > 14 ? this._getByDependency(deps[14], binding.key) : null;
d15 = length > 15 ? this._getByDependency(deps[15], binding.key) : null;
d16 = length > 16 ? this._getByDependency(deps[16], binding.key) : null;
d17 = length > 17 ? this._getByDependency(deps[17], binding.key) : null;
d18 = length > 18 ? this._getByDependency(deps[18], binding.key) : null;
d19 = length > 19 ? this._getByDependency(deps[19], binding.key) : null;
d0 = length > 0 ? this._getByDependency(deps[0], visibility) : null;
d1 = length > 1 ? this._getByDependency(deps[1], visibility) : null;
d2 = length > 2 ? this._getByDependency(deps[2], visibility) : null;
d3 = length > 3 ? this._getByDependency(deps[3], visibility) : null;
d4 = length > 4 ? this._getByDependency(deps[4], visibility) : null;
d5 = length > 5 ? this._getByDependency(deps[5], visibility) : null;
d6 = length > 6 ? this._getByDependency(deps[6], visibility) : null;
d7 = length > 7 ? this._getByDependency(deps[7], visibility) : null;
d8 = length > 8 ? this._getByDependency(deps[8], visibility) : null;
d9 = length > 9 ? this._getByDependency(deps[9], visibility) : null;
d10 = length > 10 ? this._getByDependency(deps[10], visibility) : null;
d11 = length > 11 ? this._getByDependency(deps[11], visibility) : null;
d12 = length > 12 ? this._getByDependency(deps[12], visibility) : null;
d13 = length > 13 ? this._getByDependency(deps[13], visibility) : null;
d14 = length > 14 ? this._getByDependency(deps[14], visibility) : null;
d15 = length > 15 ? this._getByDependency(deps[15], visibility) : null;
d16 = length > 16 ? this._getByDependency(deps[16], visibility) : null;
d17 = length > 17 ? this._getByDependency(deps[17], visibility) : null;
d18 = length > 18 ? this._getByDependency(deps[18], visibility) : null;
d19 = length > 19 ? this._getByDependency(deps[19], visibility) : null;
} catch (e) {
if (e instanceof AbstractBindingError) e.addKey(binding.key);
throw e;
@ -656,38 +678,37 @@ export class Injector {
return obj;
}
private _getByDependency(dep: any, requestor: Key): any {
var special = isPresent(this._ei) ? this._ei.getDependency(dep) : undefinedValue;
private _getByDependency(dep: Dependency, bindingVisibility: number): any {
var special = isPresent(this.ei) ? this.ei.getDependency(dep) : undefinedValue;
if (special !== undefinedValue) {
return special;
} else {
return this._getByKey(dep.key, dep.visibility, dep.optional, requestor);
return this._getByKey(dep.key, dep.visibility, dep.optional, bindingVisibility);
}
}
private _getByKey(key: Key, depVisibility: any, optional: boolean, requestor: Key): any {
private _getByKey(key: Key, depVisibility: Visibility, optional: boolean,
bindingVisibility: number): any {
if (key.token === Injector) {
return this;
}
var inj = this;
var ei = this._ei;
// TODO vsavkin remove after DI and EI are merged
var bindingVisibility =
isPresent(ei) && ei.isComponentKey(requestor) ? PUBLIC_AND_PRIVATE : PUBLIC;
var lastInjector = false;
var depth = depVisibility.depth;
if (!depVisibility.includeSelf) {
depth -= inj._proto.distanceToParent;
if (isPresent(inj._parent)) {
inj = inj._parent;
} else {
inj = inj._host;
bindingVisibility = depVisibility.crossComponentBoundaries ? PUBLIC : PRIVATE;
if (inj._isBoundary) {
if (depVisibility.crossBoundaries) {
bindingVisibility = PUBLIC_AND_PRIVATE;
} else {
bindingVisibility = PRIVATE;
lastInjector = true;
}
}
inj = inj._parent;
}
while (inj != null && depth >= 0) {
@ -696,25 +717,17 @@ export class Injector {
depth -= inj._proto.distanceToParent;
// we check only one mode with the PRIVATE visibility
if (bindingVisibility === PRIVATE) break;
if (lastInjector) break;
if (isPresent(inj._parent)) {
inj = inj._parent;
} else {
inj = inj._host;
bindingVisibility = depVisibility.crossComponentBoundaries ? PUBLIC : PRIVATE;
}
}
// TODO vsavkin remove after DI and EI are merged
if (isPresent(ei)) {
var appInj = <Injector>this._ei.appInjector(requestor);
if (optional) {
return appInj.getOptional(key);
} else {
return appInj.get(key);
if (inj._isBoundary) {
if (depVisibility.crossBoundaries) {
bindingVisibility = PUBLIC_AND_PRIVATE;
} else {
bindingVisibility = PRIVATE;
lastInjector = true;
}
}
inj = inj._parent;
}
if (optional) {
@ -723,12 +736,6 @@ export class Injector {
throw new NoBindingError(key);
}
}
// TODO vsavkin remove after DI and EI are merged
getAppInjector(): Injector {
if (isBlank(this._ei)) return this;
return <Injector>this._ei.appInjector(null);
}
}

View File

@ -14,7 +14,7 @@ import * as modelModule from './model';
*
* @Component({
* selector: 'login-comp',
* appInjector: [
* viewInjector: [
* FormBuilder
* ]
* })

View File

@ -66,7 +66,7 @@ export class XHRConnection implements Connection {
* ```
* import {Http, MyNodeBackend, httpInjectables, BaseRequestOptions} from 'angular2/http';
* @Component({
* appInjector: [
* viewInjector: [
* httpInjectables,
* bind(Http).toFactory((backend, options) => {
* return new Http(backend, options);

View File

@ -52,7 +52,7 @@ function mergeOptions(defaultOpts, providedOpts, method, url): RequestOptions {
*
* ```
* import {Http, httpInjectables} from 'angular2/http';
* @Component({selector: 'http-app', appInjector: [httpInjectables]})
* @Component({selector: 'http-app', viewInjector: [httpInjectables]})
* @View({templateUrl: 'people.html'})
* class PeopleComponent {
* constructor(http: Http) {

View File

@ -3,7 +3,7 @@ import {isBlank, isPresent} from 'angular2/src/facade/lang';
import {Directive, Attribute} from 'angular2/src/core/annotations/decorators';
import {DynamicComponentLoader, ComponentRef, ElementRef} from 'angular2/core';
import {Injector, bind} from 'angular2/di';
import {Injector, bind, Dependency, undefinedValue} from 'angular2/di';
import * as routerMod from './router';
import {Instruction, RouteParams} from './instruction'
@ -24,20 +24,14 @@ import {Instruction, RouteParams} from './instruction'
export class RouterOutlet {
private _childRouter: routerMod.Router = null;
private _componentRef: ComponentRef = null;
private _elementRef: ElementRef;
private _currentInstruction: Instruction = null;
private _injector: Injector;
constructor(elementRef: ElementRef, private _loader: DynamicComponentLoader,
private _parentRouter: routerMod.Router, _injector: Injector,
@Attribute('name') nameAttr: string) {
constructor(private _elementRef: ElementRef, private _loader: DynamicComponentLoader,
private _parentRouter: routerMod.Router, @Attribute('name') nameAttr: string) {
// TODO: reintroduce with new // sibling routes
// if (isBlank(nameAttr)) {
// nameAttr = 'default';
//}
this._injector = _injector.getAppInjector();
this._elementRef = elementRef;
this._parentRouter.registerOutlet(this);
}
@ -55,15 +49,13 @@ export class RouterOutlet {
this._currentInstruction = instruction;
this._childRouter = this._parentRouter.childRouter(instruction.component);
var outletInjector = this._injector.resolveAndCreateChild([
bind(RouteParams)
.toValue(new RouteParams(instruction.params())),
bind(routerMod.Router).toValue(this._childRouter)
]);
var params = new RouteParams(instruction.params());
var bindings = Injector.resolve(
[bind(RouteParams).toValue(params), bind(routerMod.Router).toValue(this._childRouter)]);
return this.deactivate()
.then((_) => this._loader.loadNextToLocation(instruction.component, this._elementRef,
outletInjector))
bindings))
.then((componentRef) => {
this._componentRef = componentRef;
return this._childRouter.commit(instruction.child);