diff --git a/modules/angular2/di.ts b/modules/angular2/di.ts index 6ee7542059..71fd8487bb 100644 --- a/modules/angular2/di.ts +++ b/modules/angular2/di.ts @@ -36,9 +36,7 @@ export { PUBLIC_AND_PRIVATE, PUBLIC, PRIVATE, - undefinedValue, - InjectorInlineStrategy, - InjectorDynamicStrategy + undefinedValue } from './src/di/injector'; export {Binding, BindingBuilder, ResolvedBinding, Dependency, bind} from './src/di/binding'; export {Key, KeyRegistry, TypeLiteral} from './src/di/key'; diff --git a/modules/angular2/docs/core/02_directives.md b/modules/angular2/docs/core/02_directives.md index 1b3ab96303..30584eb943 100644 --- a/modules/angular2/docs/core/02_directives.md +++ b/modules/angular2/docs/core/02_directives.md @@ -216,7 +216,7 @@ To better understand the kinds of injections which are supported in Angular we h ### Injecting Services -Service injection is the most straight forward kind of injection which Angular supports. It involves a component configuring the `appInjector` and then letting the directive ask for the configured service. +Service injection is the most straight forward kind of injection which Angular supports. It involves a component configuring the `viewInjector` or `hostInjector` and then letting the directive ask for the configured service. This example illustrates how to inject `MyService` into `House` directive. @@ -227,7 +227,7 @@ class MyService {} | Assume a service which needs to be inject | @Component({ | Assume a top level application component which selector: 'my-app', | configures the services to be injected. - appInjector: [MyService] | + viewInjector: [MyService] | }) | @View({ | Assume we have a template that needs to be templateUrl: 'my_app.html', | configured with directives to be injected. @@ -329,8 +329,7 @@ Shadow DOM provides an encapsulation for components, so as a general rule it doe ``` @Component({ - selector: '[kid]', - appInjector: [] + selector: '[kid]' }) @View({ templateUrl: 'kid.html', @@ -348,8 +347,7 @@ class Kid { } @Component({ - selector: '[dad]', - appInjector: [Grandpa] + selector: '[dad]' }) @View({ templateUrl: 'dad.html', @@ -364,7 +362,7 @@ class Dad { @Component({ selector: '[grandpa]', - appInjector: [] + viewInjector: [] }) @View({ templateUrl: 'grandpa.html', diff --git a/modules/angular2/http.ts b/modules/angular2/http.ts index b1d52a7d43..58b41e3436 100644 --- a/modules/angular2/http.ts +++ b/modules/angular2/http.ts @@ -48,7 +48,7 @@ export {URLSearchParams} from 'angular2/src/http/url_search_params'; * * ``` * import {httpInjectables, Http} from 'angular2/http'; - * @Component({selector: 'http-app', appInjector: [httpInjectables]}) + * @Component({selector: 'http-app', viewInjector: [httpInjectables]}) * @View({template: '{{data}}'}) * class MyApp { * constructor(http:Http) { diff --git a/modules/angular2/src/core/annotations_impl/annotations.ts b/modules/angular2/src/core/annotations_impl/annotations.ts index 3e2fac9baf..e4a0027619 100644 --- a/modules/angular2/src/core/annotations_impl/annotations.ts +++ b/modules/angular2/src/core/annotations_impl/annotations.ts @@ -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; - /** * 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; - 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; viewInjector?: List; changeDetection?: string; } diff --git a/modules/angular2/src/core/application.ts b/modules/angular2/src/core/application.ts index 1672cb7aa8..d0a4b6549c 100644 --- a/modules/angular2/src/core/application.ts +++ b/modules/angular2/src/core/application.ts @@ -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. * diff --git a/modules/angular2/src/core/compiler/dynamic_component_loader.ts b/modules/angular2/src/core/compiler/dynamic_component_loader.ts index 7da92d3d4a..f188547a64 100644 --- a/modules/angular2/src/core/compiler/dynamic_component_loader.ts +++ b/modules/angular2/src/core/compiler/dynamic_component_loader.ts @@ -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 { + loadAsRoot(typeOrBinding: Type | Binding, overrideSelector: string, + injector: Injector): Promise { 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 { + bindings: ResolvedBinding[] = null): Promise { 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 { + bindings: ResolvedBinding[] = null): Promise { 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); diff --git a/modules/angular2/src/core/compiler/element_injector.ts b/modules/angular2/src/core/compiler/element_injector.ts index 8771509085..8eed251d4a 100644 --- a/modules/angular2/src/core/compiler/element_injector.ts +++ b/modules/angular2/src/core/compiler/element_injector.ts @@ -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, - public resolvedAppInjectables: List, public resolvedHostInjectables: List, public resolvedViewInjectables: List, 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 = 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 { - if (!(this.binding instanceof DirectiveBinding)) return []; - var db = 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 = 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 = 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): 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, - bd: List, - firstBindingIsComponent: boolean) { + private static _createDirectiveBindingWithVisibility(dirBindings: List, + 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, - bd: List, - firstBindingIsComponent: boolean) { + private static _createHostInjectorBindingWithVisibility(dirBindings: List, + 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, - bd: List) { + private static _createViewInjectorBindingWithVisibility(bindings: List, + bd: BindingWithVisibility[]) { var db = 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, + constructor(public parent: ProtoElementInjector, public index: int, bwv: BindingWithVisibility[], public distanceToParent: number, public _firstBindingIsComponent: boolean, public directiveVariableBindings: Map) { - 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 { - 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 { 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 = this._injector.strategy; + var injectorStrategy = this._injector.internalStrategy; this._strategy = injectorStrategy instanceof InjectorInlineStrategy ? new ElementInjectorInlineStrategy( injectorStrategy, this) : @@ -472,10 +468,8 @@ export class ElementInjector extends TreeNode { 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 { } } - 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 { 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 { return isPresent(index) ? this.getDirectiveAtIndex(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 { 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 { 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; } diff --git a/modules/angular2/src/core/compiler/proto_view_factory.ts b/modules/angular2/src/core/compiler/proto_view_factory.ts index 84a2c71f49..ae785e7499 100644 --- a/modules/angular2/src/core/compiler/proto_view_factory.ts +++ b/modules/angular2/src/core/compiler/proto_view_factory.ts @@ -348,7 +348,7 @@ function _findParentProtoElementInjectorWithDistance( } } } while (binderIndex !== -1); - return new ParentProtoElementInjectorWithDistance(null, -1); + return new ParentProtoElementInjectorWithDistance(null, 0); } function _createProtoElementInjector(binderIndex, parentPeiWithDistance, renderElementBinder, diff --git a/modules/angular2/src/core/compiler/view_container_ref.ts b/modules/angular2/src/core/compiler/view_container_ref.ts index 419c46c5e5..9ccfcc18a6 100644 --- a/modules/angular2/src/core/compiler/view_container_ref.ts +++ b/modules/angular2/src/core/compiler/view_container_ref.ts @@ -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 { diff --git a/modules/angular2/src/core/compiler/view_manager.ts b/modules/angular2/src/core/compiler/view_manager.ts index fa072d925f..56fb7ff0dc 100644 --- a/modules/angular2/src/core/compiler/view_manager.ts +++ b/modules/angular2/src/core/compiler/view_manager.ts @@ -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; } diff --git a/modules/angular2/src/core/compiler/view_manager_utils.ts b/modules/angular2/src/core/compiler/view_manager_utils.ts index 2ba7b27b00..464c51da2c 100644 --- a/modules/angular2/src/core/compiler/view_manager_utils.ts +++ b/modules/angular2/src/core/compiler/view_manager_utils.ts @@ -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); diff --git a/modules/angular2/src/core/exception_handler.ts b/modules/angular2/src/core/exception_handler.ts index d60d914ade..a9cf25f519 100644 --- a/modules/angular2/src/core/exception_handler.ts +++ b/modules/angular2/src/core/exception_handler.ts @@ -15,7 +15,7 @@ import {DOM} from 'angular2/src/dom/dom_adapter'; * ```javascript * @Component({ * selector: 'my-app', - * appInjector: [ + * viewInjector: [ * bind(ExceptionHandler).toClass(MyExceptionHandler) * ] * }) diff --git a/modules/angular2/src/di/annotations_impl.ts b/modules/angular2/src/di/annotations_impl.ts index 0b68ba1a2a..71392168fd 100644 --- a/modules/angular2/src/di/annotations_impl.ts +++ b/modules/angular2/src/di/annotations_impl.ts @@ -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}})`; } } diff --git a/modules/angular2/src/di/injector.ts b/modules/angular2/src/di/injector.ts index 393a391df1..c337d7581a 100644 --- a/modules/angular2/src/di/injector.ts +++ b/modules/angular2/src/di/injector.ts @@ -1,7 +1,7 @@ /// 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>, - {defaultBindings = false}: any = {}): Injector { + static resolveAndCreate(bindings: List>): 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, - {defaultBindings = false}: any = {}): Injector { - var bd = bindings.map(b => new BindingData(b, PUBLIC)); - var proto = new ProtoInjector(null, bd, 0); + static fromResolvedBindings(bindings: List): 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>): 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): 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 = 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 this._ei.appInjector(null); - } } diff --git a/modules/angular2/src/forms/form_builder.ts b/modules/angular2/src/forms/form_builder.ts index 3abf78018e..6d33c363ea 100644 --- a/modules/angular2/src/forms/form_builder.ts +++ b/modules/angular2/src/forms/form_builder.ts @@ -14,7 +14,7 @@ import * as modelModule from './model'; * * @Component({ * selector: 'login-comp', - * appInjector: [ + * viewInjector: [ * FormBuilder * ] * }) diff --git a/modules/angular2/src/http/backends/xhr_backend.ts b/modules/angular2/src/http/backends/xhr_backend.ts index 385757611a..b7cd90bbc3 100644 --- a/modules/angular2/src/http/backends/xhr_backend.ts +++ b/modules/angular2/src/http/backends/xhr_backend.ts @@ -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); diff --git a/modules/angular2/src/http/http.ts b/modules/angular2/src/http/http.ts index 068ad25bf7..f1508f80c3 100644 --- a/modules/angular2/src/http/http.ts +++ b/modules/angular2/src/http/http.ts @@ -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) { diff --git a/modules/angular2/src/router/router_outlet.ts b/modules/angular2/src/router/router_outlet.ts index 04ac6adf10..0e51c3616c 100644 --- a/modules/angular2/src/router/router_outlet.ts +++ b/modules/angular2/src/router/router_outlet.ts @@ -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); diff --git a/modules/angular2/test/core/compiler/dynamic_component_loader_spec.ts b/modules/angular2/test/core/compiler/dynamic_component_loader_spec.ts index 731b367972..038e717fbb 100644 --- a/modules/angular2/test/core/compiler/dynamic_component_loader_spec.ts +++ b/modules/angular2/test/core/compiler/dynamic_component_loader_spec.ts @@ -266,7 +266,7 @@ class DynamicallyCreatedComponentService {} @Component({ selector: 'hello-cmp', - appInjector: [DynamicallyCreatedComponentService], + viewInjector: [DynamicallyCreatedComponentService], lifecycle: [onDestroy] }) @View({template: "{{greeting}}"}) diff --git a/modules/angular2/test/core/compiler/element_injector_spec.ts b/modules/angular2/test/core/compiler/element_injector_spec.ts index e11217ec89..27435b42e6 100644 --- a/modules/angular2/test/core/compiler/element_injector_spec.ts +++ b/modules/angular2/test/core/compiler/element_injector_spec.ts @@ -242,8 +242,7 @@ class TestNode extends TreeNode { export function main() { var defaultPreBuiltObjects = new PreBuiltObjects(null, new DummyView(1), null); - var appInjector = Injector.resolveAndCreate([]); - + // An injector with more than 10 bindings will switch to the dynamic strategy var dynamicBindings = []; @@ -269,48 +268,41 @@ export function main() { return [lookupName(tree), children]; } - function injector(bindings, lightDomAppInjector = null, isComponent: boolean = false, + function injector(bindings, imperativelyCreatedInjector = null, isComponent: boolean = false, preBuiltObjects = null, attributes = null, dirVariableBindings = null) { - if (isBlank(lightDomAppInjector)) lightDomAppInjector = appInjector; - var proto = createPei(null, 0, bindings, 0, isComponent, dirVariableBindings); proto.attributes = attributes; var inj = proto.instantiate(null); var preBuilt = isPresent(preBuiltObjects) ? preBuiltObjects : defaultPreBuiltObjects; - inj.hydrate(lightDomAppInjector, null, preBuilt); + inj.hydrate(imperativelyCreatedInjector, null, preBuilt); return inj; } function parentChildInjectors(parentBindings, childBindings, parentPreBuildObjects = null) { if (isBlank(parentPreBuildObjects)) parentPreBuildObjects = defaultPreBuiltObjects; - var inj = Injector.resolveAndCreate([]); - - var protoParent = createPei(null, 0, parentBindings); var parent = protoParent.instantiate(null); - parent.hydrate(inj, null, parentPreBuildObjects); + parent.hydrate(null, null, parentPreBuildObjects); var protoChild = createPei(protoParent, 1, childBindings, 1, false); var child = protoChild.instantiate(parent); - child.hydrate(inj, null, defaultPreBuiltObjects); + child.hydrate(null, null, defaultPreBuiltObjects); return child; } function hostShadowInjectors(hostBindings: List, shadowBindings: List): ElementInjector { - var inj = Injector.resolveAndCreate([]); - var protoHost = createPei(null, 0, hostBindings, 0, true); var host = protoHost.instantiate(null); - host.hydrate(inj, null, defaultPreBuiltObjects); + host.hydrate(null, null, defaultPreBuiltObjects); var protoShadow = createPei(null, 0, shadowBindings, 0, false); var shadow = protoShadow.instantiate(null); - shadow.hydrate(host.getShadowDomAppInjector(), host, null); + shadow.hydrate(null, host, null); return shadow; } @@ -570,6 +562,7 @@ export function main() { var extraBindings = context['bindings']; describe(`${context['strategy']} strategy`, () => { + describe("hydrate", () => { it("should instantiate directives that have no dependencies", () => { var bindings = ListWrapper.concat([SimpleDirective], extraBindings); @@ -609,22 +602,42 @@ export function main() { }); it("should instantiate hostInjector injectables that have dependencies", () => { - var inj = injector(ListWrapper.concat( - [DirectiveBinding.createFromType(SimpleDirective, new dirAnn.Directive({ - hostInjector: [ + var hostInjector = [ bind('injectable1') .toValue('injectable1'), bind('injectable2') .toFactory( (val) => `${val}-injectable2`, ['injectable1']) - ] - }))], + ]; + + var inj = injector(ListWrapper.concat( + [DirectiveBinding.createFromType(SimpleDirective, + new dirAnn.Directive({hostInjector: hostInjector}))], extraBindings)); + expect(inj.get('injectable2')).toEqual('injectable1-injectable2'); }); - - it("should instantiate components that depends on viewInjector dependencies", () => { + + it("should instantiate viewInjector injectables that have dependencies", () => { + var viewInjector = [ + bind('injectable1') + .toValue('injectable1'), + bind('injectable2') + .toFactory( + (val) => `${val}-injectable2`, + ['injectable1']) + ]; + + + var inj = injector(ListWrapper.concat( + [DirectiveBinding.createFromType(SimpleDirective, new dirAnn.Component({ + viewInjector: viewInjector}))], extraBindings), + null, true); + expect(inj.get('injectable2')).toEqual('injectable1-injectable2'); + }); + + it("should instantiate components that depend on viewInjector bindings", () => { var inj = injector( ListWrapper.concat([DirectiveBinding.createFromType(NeedsService, new dirAnn.Component({ viewInjector: [bind('service').toValue('service')] @@ -634,16 +647,19 @@ export function main() { expect(inj.get(NeedsService).service).toEqual('service'); }); - it("should prioritize viewInjector over hostInjector for the same binding", () => { - var inj = injector( - ListWrapper.concat([DirectiveBinding.createFromType(NeedsService, new dirAnn.Component({ - hostInjector: [bind('service').toValue('hostService')], - viewInjector: [bind('service').toValue('viewService')]}) - )], extraBindings), null, true); - expect(inj.get(NeedsService).service).toEqual('viewService'); - }); - - it("should instantiate a directive in a view that depends on hostInjector bindings of the component", () => { + it("should not instantiate other directives that depend on viewInjector bindings", + () => { + var directiveAnnotation = new dirAnn.Component({ + viewInjector: ListWrapper.concat([bind("service").toValue("service")], extraBindings) + }); + var componentDirective = + DirectiveBinding.createFromType(SimpleDirective, directiveAnnotation); + expect(() => { injector([componentDirective, NeedsService], null); }) + .toThrowError(containsRegexp( + `No provider for service! (${stringify(NeedsService) } -> service)`)); + }); + + it("should instantiate directives that depend on hostInjector bindings of other directives", () => { var shadowInj = hostShadowInjectors( ListWrapper.concat([DirectiveBinding.createFromType(SimpleDirective, new dirAnn.Component({ hostInjector: [bind('service').toValue('hostService')]}) @@ -652,6 +668,23 @@ export function main() { ); expect(shadowInj.get(NeedsService).service).toEqual('hostService'); }); + + it("should instantiate directives that depend on imperativley created injector bindings", () => { + var imperativelyCreatedInjector = Injector.resolveAndCreate([ + bind("service").toValue('appService') + ]); + var inj = injector([NeedsService], imperativelyCreatedInjector); + expect(inj.get(NeedsService).service).toEqual('appService'); + }); + + it("should prioritize viewInjector over hostInjector for the same binding", () => { + var inj = injector( + ListWrapper.concat([DirectiveBinding.createFromType(NeedsService, new dirAnn.Component({ + hostInjector: [bind('service').toValue('hostService')], + viewInjector: [bind('service').toValue('viewService')]}) + )], extraBindings), null, true); + expect(inj.get(NeedsService).service).toEqual('viewService'); + }); it("should not instantiate a directive in a view that has an ancestor dependency on hostInjector"+ " bindings of a decorator directive", () => { @@ -668,16 +701,6 @@ export function main() { }).toThrowError(new RegExp("No provider for service!")); }); - it("should instantiate directives that depend on app services", () => { - var appInjector = Injector.resolveAndCreate( - ListWrapper.concat([bind("service").toValue("service")], extraBindings)); - var inj = injector([NeedsService], appInjector); - - var d = inj.get(NeedsService); - expect(d).toBeAnInstanceOf(NeedsService); - expect(d.service).toEqual("service"); - }); - it("should instantiate directives that depend on pre built objects", () => { var protoView = new AppProtoView(null, null, null, null); var bindings = ListWrapper.concat([NeedsProtoViewRef], extraBindings); @@ -686,14 +709,6 @@ export function main() { expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView)); }); - it("should return app services", () => { - var appInjector = Injector.resolveAndCreate( - ListWrapper.concat([bind("service").toValue("service")], extraBindings)); - var inj = injector([], appInjector); - - expect(inj.get('service')).toEqual('service'); - }); - it("should get directives from parent", () => { var child = parentChildInjectors(ListWrapper.concat([SimpleDirective], extraBindings), [NeedsDirectiveFromParent]); @@ -752,7 +767,7 @@ export function main() { expect(d.dependency).toEqual(null); }); - it("should accept bindings instead types", () => { + it("should accept bindings instead of types", () => { var inj = injector( ListWrapper.concat([bind(SimpleDirective).toClass(SimpleDirective)], extraBindings)); expect(inj.get(SimpleDirective)).toBeAnInstanceOf(SimpleDirective); @@ -772,8 +787,6 @@ export function main() { .toThrowError(`Index ${firsIndexOut} is out-of-bounds.`); }); - - describe("shadow DOM components", () => { it("should instantiate directives that depend on the containing component", () => { var directiveBinding = DirectiveBinding.createFromType(SimpleDirective, new dirAnn.Component()); @@ -798,33 +811,6 @@ export function main() { .toThrowError(containsRegexp( `No provider for ${stringify(SimpleDirective) }! (${stringify(NeedsDirective) } -> ${stringify(SimpleDirective) })`)); }); - - it("should instantiate component directives that depend on app services in the shadow app injector", - () => { - var directiveAnnotation = new dirAnn.Component({ - appInjector: ListWrapper.concat([bind("service").toValue("service")], extraBindings) - }); - var componentDirective = - DirectiveBinding.createFromType(NeedsService, directiveAnnotation); - var inj = injector([componentDirective], null, true); - - var d = inj.get(NeedsService); - expect(d).toBeAnInstanceOf(NeedsService); - expect(d.service).toEqual("service"); - }); - - it("should not instantiate other directives that depend on app services in the shadow app injector", - () => { - var directiveAnnotation = new dirAnn.Component({ - appInjector: ListWrapper.concat([bind("service").toValue("service")], extraBindings) - }); - var componentDirective = - DirectiveBinding.createFromType(SimpleDirective, directiveAnnotation); - expect(() => { injector([componentDirective, NeedsService], null); }) - .toThrowError(containsRegexp( - `No provider for service! (${stringify(NeedsService) } -> service)`)); - }); - }); }); describe("lifecycle", () => { @@ -1058,8 +1044,8 @@ export function main() { var parent = protoParent.instantiate(null); var child = protoChild.instantiate(parent); - parent.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects); - child.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects); + parent.hydrate(null, null, preBuildObjects); + child.hydrate(null, null, preBuildObjects); expectDirectives(parent.get(NeedsQuery).query, CountingDirective, [0, 1]); }); @@ -1071,8 +1057,8 @@ export function main() { var parent = protoParent.instantiate(null); var child = protoChild.instantiate(parent); - parent.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects); - child.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects); + parent.hydrate(null, null, preBuildObjects); + child.hydrate(null, null, preBuildObjects); child.unlink(); @@ -1089,9 +1075,9 @@ export function main() { var child1 = protoChild1.instantiate(parent); var child2 = protoChild2.instantiate(parent); - parent.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects); - child1.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects); - child2.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects); + parent.hydrate(null, null, preBuildObjects); + child1.hydrate(null, null, preBuildObjects); + child2.hydrate(null, null, preBuildObjects); child1.unlink(); child1.link(parent); @@ -1110,9 +1096,9 @@ export function main() { var child1 = protoChild1.instantiate(parent); var child2 = protoChild2.instantiate(parent); - parent.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects); - child1.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects); - child2.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects); + parent.hydrate(null, null, preBuildObjects); + child1.hydrate(null, null, preBuildObjects); + child2.hydrate(null, null, preBuildObjects); child2.unlink(); child2.linkAfter(parent, null); @@ -1131,9 +1117,9 @@ export function main() { var parent = protoParent.instantiate(grandParent); var child = protoChild.instantiate(parent); - grandParent.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects); - parent.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects); - child.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects); + grandParent.hydrate(null, null, preBuildObjects); + parent.hydrate(null, null, preBuildObjects); + child.hydrate(null, null, preBuildObjects); var queryList1 = grandParent.get(NeedsQuery).query; var queryList2 = parent.get(NeedsQuery).query; diff --git a/modules/angular2/test/core/compiler/integration_dart_spec.dart b/modules/angular2/test/core/compiler/integration_dart_spec.dart index 64c9c7bdce..068a9186eb 100644 --- a/modules/angular2/test/core/compiler/integration_dart_spec.dart +++ b/modules/angular2/test/core/compiler/integration_dart_spec.dart @@ -38,7 +38,7 @@ void functionThatThrowsNonError() { main() { describe('TypeLiteral', () { - it('should publish via appInjector', inject([ + it('should publish via viewInjector', inject([ TestComponentBuilder, AsyncTestCompleter ], (tb, async) { @@ -143,7 +143,7 @@ class Dummy {} @Component( selector: 'type-literal-component', - appInjector: const [ + viewInjector: const [ const Binding(const TypeLiteral>(), toValue: const ['Hello', 'World']) ]) diff --git a/modules/angular2/test/core/compiler/integration_spec.ts b/modules/angular2/test/core/compiler/integration_spec.ts index 78daf1bad0..e5bf701014 100644 --- a/modules/angular2/test/core/compiler/integration_spec.ts +++ b/modules/angular2/test/core/compiler/integration_spec.ts @@ -1319,18 +1319,17 @@ class SimpleImperativeViewComponent { } } - @Directive({selector: 'dynamic-vp'}) @Injectable() class DynamicViewport { done; - constructor(vc: ViewContainerRef, inj: Injector, compiler: Compiler) { + constructor(vc: ViewContainerRef, compiler: Compiler) { var myService = new MyService(); myService.greeting = 'dynamic greet'; + + var bindings = Injector.resolve([bind(MyService).toValue(myService)]); this.done = compiler.compileInHost(ChildCompUsingService) - .then((hostPv) => {vc.create(hostPv, 0, null, - inj.createChildFromResolved(Injector.resolve( - [bind(MyService).toValue(myService)])))}); + .then((hostPv) => {vc.create(hostPv, 0, null, bindings)}); } } @@ -1398,7 +1397,7 @@ class ComponentWithPipes { prop: string; } -@Component({selector: 'child-cmp', properties: ['dirProp'], appInjector: [MyService]}) +@Component({selector: 'child-cmp', properties: ['dirProp'], viewInjector: [MyService]}) @View({directives: [MyDir], template: '{{ctxProp}}'}) @Injectable() class ChildComp { @@ -1448,7 +1447,7 @@ class CompWithAncestor { constructor(@Ancestor() someComp: SomeDirective) { this.myAncestor = someComp; } } -@Component({selector: '[child-cmp2]', appInjector: [MyService]}) +@Component({selector: '[child-cmp2]', viewInjector: [MyService]}) @Injectable() class ChildComp2 { ctxProp: string; diff --git a/modules/angular2/test/core/compiler/proto_view_factory_spec.ts b/modules/angular2/test/core/compiler/proto_view_factory_spec.ts index 7002eec178..ea5141c03f 100644 --- a/modules/angular2/test/core/compiler/proto_view_factory_spec.ts +++ b/modules/angular2/test/core/compiler/proto_view_factory_spec.ts @@ -156,7 +156,7 @@ export function main() { } function directiveBinding({metadata}: {metadata?: any} = {}) { - return new DirectiveBinding(Key.get("dummy"), null, [], [], [], [], metadata); + return new DirectiveBinding(Key.get("dummy"), null, [], [], [], metadata); } function createRenderProtoView(elementBinders = null, type: renderApi.ViewType = null) { diff --git a/modules/angular2/test/core/compiler/view_manager_spec.ts b/modules/angular2/test/core/compiler/view_manager_spec.ts index 3d2206013e..014d531496 100644 --- a/modules/angular2/test/core/compiler/view_manager_spec.ts +++ b/modules/angular2/test/core/compiler/view_manager_spec.ts @@ -301,13 +301,12 @@ export function main() { }); it('should hydrate the view', () => { - var injector = Injector.resolveAndCreate([]); var contextView = createView(createProtoView([createEmptyElBinder(), createEmptyElBinder()])); manager.createViewInContainer(elementRef(parentView, 0), 0, wrapPv(childProtoView), - elementRef(contextView, 1), injector); + elementRef(contextView, 1), []); expect(utils.spy('hydrateViewInContainer')) - .toHaveBeenCalledWith(parentView, 0, contextView, 1, 0, injector); + .toHaveBeenCalledWith(parentView, 0, contextView, 1, 0, []); expect(renderer.spy('hydrateView')).toHaveBeenCalledWith(createdViews[0].render); }); diff --git a/modules/angular2/test/core/compiler/view_manager_utils_spec.ts b/modules/angular2/test/core/compiler/view_manager_utils_spec.ts index 0c205c130b..abff81ccbb 100644 --- a/modules/angular2/test/core/compiler/view_manager_utils_spec.ts +++ b/modules/angular2/test/core/compiler/view_manager_utils_spec.ts @@ -69,7 +69,6 @@ export function main() { function createElementInjector(parent = null) { var host = new SpyElementInjector(); - var appInjector = new SpyInjector(); var elementInjector = isPresent(parent) ? new SpyElementInjectorWithParent(parent) : new SpyElementInjector(); return SpyObject.stub(elementInjector, @@ -79,8 +78,7 @@ export function main() { 'getEventEmitterAccessors': [], 'getHostActionAccessors': [], 'getComponent': null, - 'getHost': host, - 'getShadowDomAppInjector': appInjector + 'getHost': host }, {}); } @@ -245,17 +243,6 @@ export function main() { .toHaveBeenCalledWith(null, contextView.elementInjectors[0].getHost(), childView.preBuiltObjects[0]); }); - - it('should use the shadowDomAppInjector of the context elementInjector if there is no host', - () => { - createViews(); - parentView.elementInjectors[0].spy('getHost').andReturn(null); - utils.hydrateViewInContainer(parentView, 0, parentView, 0, 0, null); - expect(childView.rootElementInjectors[0].spy('hydrate')) - .toHaveBeenCalledWith(parentView.elementInjectors[0].getShadowDomAppInjector(), null, - childView.preBuiltObjects[0]); - }); - }); describe('hydrateRootHostView', () => { diff --git a/modules/angular2/test/core/forward_ref_integration_spec.ts b/modules/angular2/test/core/forward_ref_integration_spec.ts index 8ca5aca822..e34cef3a41 100644 --- a/modules/angular2/test/core/forward_ref_integration_spec.ts +++ b/modules/angular2/test/core/forward_ref_integration_spec.ts @@ -29,7 +29,7 @@ export function main() { }); } -@Component({selector: 'app', appInjector: [forwardRef(() => Frame)]}) +@Component({selector: 'app', viewInjector: [forwardRef(() => Frame)]}) @View({ template: ``, directives: [ diff --git a/modules/angular2/test/debug/debug_element_spec.ts b/modules/angular2/test/debug/debug_element_spec.ts index 1847ac7307..9a2078339c 100644 --- a/modules/angular2/test/debug/debug_element_spec.ts +++ b/modules/angular2/test/debug/debug_element_spec.ts @@ -66,7 +66,7 @@ class ChildComp { constructor() { this.childBinding = 'Original'; } } -@Component({selector: 'parent-comp', appInjector: [Logger]}) +@Component({selector: 'parent-comp', viewInjector: [Logger]}) @View({ template: `
Parent @@ -110,7 +110,7 @@ class EventsComp { handleCustom() { this.customed = true; } } -@Component({selector: 'using-for', appInjector: [Logger]}) +@Component({selector: 'using-for', viewInjector: [Logger]}) @View({ template: `{{thing}}
    diff --git a/modules/angular2/test/transform/directive_linker/simple_files/bar.ng_deps.dart b/modules/angular2/test/transform/directive_linker/simple_files/bar.ng_deps.dart index a475bfc4aa..2cf2b550dd 100644 --- a/modules/angular2/test/transform/directive_linker/simple_files/bar.ng_deps.dart +++ b/modules/angular2/test/transform/directive_linker/simple_files/bar.ng_deps.dart @@ -14,7 +14,7 @@ void initReflector(reflector) { 'parameters': const [], 'annotations': const [ const Component( - selector: '[soup]', appInjector: const [dep.DependencyComponent]) + selector: '[soup]', viewInjector: const [dep.DependencyComponent]) ] }); } diff --git a/modules/angular2/test/transform/directive_linker/simple_files/expected/bar.ng_deps.dart b/modules/angular2/test/transform/directive_linker/simple_files/expected/bar.ng_deps.dart index 7b923cc7d8..b713fd1aa0 100644 --- a/modules/angular2/test/transform/directive_linker/simple_files/expected/bar.ng_deps.dart +++ b/modules/angular2/test/transform/directive_linker/simple_files/expected/bar.ng_deps.dart @@ -15,7 +15,7 @@ void initReflector(reflector) { 'parameters': const [], 'annotations': const [ const Component( - selector: '[soup]', appInjector: const [dep.DependencyComponent]) + selector: '[soup]', viewInjector: const [dep.DependencyComponent]) ] }); i0.initReflector(reflector); diff --git a/modules/angular2_material/src/components/dialog/dialog.ts b/modules/angular2_material/src/components/dialog/dialog.ts index befed13b25..10fe1c6a45 100644 --- a/modules/angular2_material/src/components/dialog/dialog.ts +++ b/modules/angular2_material/src/components/dialog/dialog.ts @@ -8,7 +8,7 @@ import { ComponentRef, DomRenderer } from 'angular2/angular2'; -import {bind, Injector, Injectable, forwardRef} from 'angular2/di'; +import {bind, Injectable, forwardRef, ResolvedBinding, Injector} from 'angular2/di'; import {ObservableWrapper, Promise, PromiseWrapper} from 'angular2/src/facade/async'; import {isPresent, Type} from 'angular2/src/facade/lang'; @@ -46,17 +46,15 @@ export class MdDialog { * @param options * @returns Promise for a reference to the dialog. */ - open(type: Type, elementRef: ElementRef, parentInjector: Injector, - options: MdDialogConfig = null): Promise { + open(type: Type, elementRef: ElementRef, options: MdDialogConfig = null): Promise { var config = isPresent(options) ? options : new MdDialogConfig(); // Create the dialogRef here so that it can be injected into the content component. var dialogRef = new MdDialogRef(); - var dialogRefBinding = bind(MdDialogRef).toValue(dialogRef); - var contentInjector = parentInjector.resolveAndCreateChild([dialogRefBinding]); + var bindings = Injector.resolve([bind(MdDialogRef).toValue(dialogRef)]); - var backdropRefPromise = this._openBackdrop(elementRef, contentInjector); + var backdropRefPromise = this._openBackdrop(elementRef, bindings); // First, load the MdDialogContainer, into which the given component will be loaded. return this.componentLoader.loadNextToLocation(MdDialogContainer, elementRef) @@ -87,7 +85,7 @@ export class MdDialog { // Now load the given component into the MdDialogContainer. return this.componentLoader.loadNextToLocation(type, containerRef.instance.contentRef, - contentInjector) + bindings) .then(contentRef => { // Wrap both component refs for the container and the content so that we can return @@ -106,8 +104,8 @@ export class MdDialog { } /** Loads the dialog backdrop (transparent overlay over the rest of the page). */ - _openBackdrop(elementRef: ElementRef, injector: Injector): Promise { - return this.componentLoader.loadNextToLocation(MdBackdrop, elementRef, injector) + _openBackdrop(elementRef: ElementRef, bindings: ResolvedBinding[]): Promise { + return this.componentLoader.loadNextToLocation(MdBackdrop, elementRef, bindings) .then((componentRef) => { // TODO(tbosch): clean this up when we have custom renderers // (https://github.com/angular/angular/issues/1807) diff --git a/modules/benchmarks/src/element_injector/element_injector_benchmark.ts b/modules/benchmarks/src/element_injector/element_injector_benchmark.ts index 3082a13c08..19dc4beaee 100644 --- a/modules/benchmarks/src/element_injector/element_injector_benchmark.ts +++ b/modules/benchmarks/src/element_injector/element_injector_benchmark.ts @@ -12,8 +12,6 @@ export function main() { var iterations = getIntParameter('iterations'); reflector.reflectionCapabilities = new ReflectionCapabilities(); - var appInjector = Injector.resolveAndCreate([]); - var bindings = [ DirectiveBinding.createFromType(A, null), DirectiveBinding.createFromType(B, null), @@ -25,14 +23,14 @@ export function main() { function instantiate() { for (var i = 0; i < iterations; ++i) { var ei = proto.instantiate(null); - ei.hydrate(appInjector, null, null); + ei.hydrate(null, null, null); } } function hydrate() { for (var i = 0; i < iterations; ++i) { elementInjector.dehydrate(); - elementInjector.hydrate(appInjector, null, null); + elementInjector.hydrate(null, null, null); } } diff --git a/modules/examples/src/hello_world/index_common.ts b/modules/examples/src/hello_world/index_common.ts index 9b592d10d3..4348a0e2b1 100644 --- a/modules/examples/src/hello_world/index_common.ts +++ b/modules/examples/src/hello_world/index_common.ts @@ -29,7 +29,7 @@ class RedDec { selector: 'hello-app', // These are services that would be created if a class in the component's // template tries to inject them. - appInjector: [GreetingService] + viewInjector: [GreetingService] }) // The template for the component. @View({ diff --git a/modules/examples/src/material/dialog/index.ts b/modules/examples/src/material/dialog/index.ts index 945851fcd1..cf55f5c477 100644 --- a/modules/examples/src/material/dialog/index.ts +++ b/modules/examples/src/material/dialog/index.ts @@ -6,13 +6,13 @@ import { } from 'angular2_material/src/components/dialog/dialog'; import {UrlResolver} from 'angular2/src/services/url_resolver'; import {commonDemoSetup, DemoUrlResolver} from '../demo_common'; -import {bind, Injector} from 'angular2/di'; +import {bind} from 'angular2/di'; import {isPresent} from 'angular2/src/facade/lang'; @Component({ selector: 'demo-app', - appInjector: [MdDialog], + viewInjector: [MdDialog], }) @View({ templateUrl: './demo_app.html', @@ -23,14 +23,12 @@ class DemoApp { elementRef: ElementRef; dialogRef: MdDialogRef; dialogConfig: MdDialogConfig; - injector: Injector; lastResult: string; - constructor(mdDialog: MdDialog, elementRef: ElementRef, injector: Injector) { + constructor(mdDialog: MdDialog, elementRef: ElementRef) { this.dialog = mdDialog; this.elementRef = elementRef; this.dialogConfig = new MdDialogConfig(); - this.injector = injector; this.dialogConfig.width = '60%'; this.dialogConfig.height = '60%'; @@ -42,7 +40,7 @@ class DemoApp { return; } - this.dialog.open(SimpleDialogComponent, this.elementRef, this.injector, this.dialogConfig) + this.dialog.open(SimpleDialogComponent, this.elementRef, this.dialogConfig) .then(ref => { this.dialogRef = ref; ref.instance.numCoconuts = 777; diff --git a/modules/examples/src/material/radio/index.ts b/modules/examples/src/material/radio/index.ts index 662f59c499..82b113bcd0 100644 --- a/modules/examples/src/material/radio/index.ts +++ b/modules/examples/src/material/radio/index.ts @@ -5,7 +5,7 @@ import {UrlResolver} from 'angular2/src/services/url_resolver'; import {commonDemoSetup, DemoUrlResolver} from '../demo_common'; import {bind} from 'angular2/di'; -@Component({selector: 'demo-app', appInjector: [MdRadioDispatcher]}) +@Component({selector: 'demo-app', viewInjector: [MdRadioDispatcher]}) @View({templateUrl: './demo_app.html', directives: [MdRadioGroup, MdRadioButton]}) class DemoApp { thirdValue; diff --git a/modules/examples/src/model_driven_forms/index.ts b/modules/examples/src/model_driven_forms/index.ts index e9d8c4899f..047ad6d367 100644 --- a/modules/examples/src/model_driven_forms/index.ts +++ b/modules/examples/src/model_driven_forms/index.ts @@ -72,7 +72,7 @@ class ShowError { } -@Component({selector: 'model-driven-forms', appInjector: [FormBuilder]}) +@Component({selector: 'model-driven-forms', viewInjector: [FormBuilder]}) @View({ template: `

    Checkout Form (Model Driven)

    diff --git a/modules/examples/src/todo/index.ts b/modules/examples/src/todo/index.ts index d88a362d22..19d46e790b 100644 --- a/modules/examples/src/todo/index.ts +++ b/modules/examples/src/todo/index.ts @@ -3,7 +3,7 @@ import {Store, Todo, TodoFactory} from './services/TodoStore'; import {reflector} from 'angular2/src/reflection/reflection'; import {ReflectionCapabilities} from 'angular2/src/reflection/reflection_capabilities'; -@Component({selector: 'todo-app', appInjector: [Store, TodoFactory]}) +@Component({selector: 'todo-app', viewInjector: [Store, TodoFactory]}) @View({templateUrl: 'todo.html', directives: [NgFor]}) class TodoApp { todoEdit: Todo = null;