refactor(ElementInjector): support components
- Allow to access containing component directive instance from the shadow DOM. - Allow to access app services of the app level injector of the component when the component is instantiated.
This commit is contained in:
parent
c68e78075a
commit
7308a3acc7
|
@ -10,8 +10,8 @@ export function run () {
|
|||
var bindings = [A, B, C];
|
||||
var proto = new ProtoElementInjector(null, 0, bindings);
|
||||
for (var i = 0; i < ITERATIONS; ++i) {
|
||||
var ei = proto.instantiate(null,null);
|
||||
ei.instantiateDirectives(appInjector);
|
||||
var ei = proto.instantiate(null,null,null);
|
||||
ei.instantiateDirectives(appInjector, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ var count = 0;
|
|||
|
||||
export function run () {
|
||||
var appInjector = new Injector([]);
|
||||
|
||||
|
||||
var bindings = [
|
||||
new Binding(Key.get(A), () => new A(), [], false),
|
||||
new Binding(Key.get(B), () => new B(), [], false),
|
||||
|
@ -18,8 +18,8 @@ export function run () {
|
|||
|
||||
var proto = new ProtoElementInjector(null, 0, bindings);
|
||||
for (var i = 0; i < ITERATIONS; ++i) {
|
||||
var ei = proto.instantiate(null,null);
|
||||
ei.instantiateDirectives(appInjector);
|
||||
var ei = proto.instantiate(null,null,null);
|
||||
ei.instantiateDirectives(appInjector, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,11 @@ export function run () {
|
|||
|
||||
var bindings = [A, B, C];
|
||||
var proto = new ProtoElementInjector(null, 0, bindings);
|
||||
var ei = proto.instantiate(null,null);
|
||||
var ei = proto.instantiate(null,null,null);
|
||||
|
||||
for (var i = 0; i < ITERATIONS; ++i) {
|
||||
ei.clearDirectives();
|
||||
ei.instantiateDirectives(appInjector);
|
||||
ei.instantiateDirectives(appInjector, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {FIELD, isPresent, isBlank, Type, int} from 'facade/lang';
|
||||
import {FIELD, isPresent, isBlank, Type, int, BaseException} from 'facade/lang';
|
||||
import {Math} from 'facade/math';
|
||||
import {List, ListWrapper} from 'facade/collection';
|
||||
import {Injector, Key, Dependency, bind, Binding, NoProviderError, ProviderError, CyclicDependencyError} from 'di/di';
|
||||
|
@ -106,6 +106,7 @@ export class ProtoElementInjector {
|
|||
@FIELD('_binding7:Binding')
|
||||
@FIELD('_binding8:Binding')
|
||||
@FIELD('_binding9:Binding')
|
||||
@FIELD('_binding0IsComponent:int')
|
||||
@FIELD('_key0:int')
|
||||
@FIELD('_key1:int')
|
||||
@FIELD('_key2:int')
|
||||
|
@ -118,10 +119,11 @@ export class ProtoElementInjector {
|
|||
@FIELD('_key9:int')
|
||||
@FIELD('final parent:ProtoElementInjector')
|
||||
@FIELD('final index:int')
|
||||
constructor(parent:ProtoElementInjector, index:int, bindings:List) {
|
||||
constructor(parent:ProtoElementInjector, index:int, bindings:List, firstBindingIsComponent:boolean = false) {
|
||||
this.parent = parent;
|
||||
this.index = index;
|
||||
|
||||
this._binding0IsComponent = firstBindingIsComponent;
|
||||
this._binding0 = null; this._keyId0 = null;
|
||||
this._binding1 = null; this._keyId1 = null;
|
||||
this._binding2 = null; this._keyId2 = null;
|
||||
|
@ -150,8 +152,8 @@ export class ProtoElementInjector {
|
|||
}
|
||||
}
|
||||
|
||||
instantiate(parent:ElementInjector, view):ElementInjector {
|
||||
return new ElementInjector(this, parent, view);
|
||||
instantiate(parent:ElementInjector, host:ElementInjector, view):ElementInjector {
|
||||
return new ElementInjector(this, parent, host, view);
|
||||
}
|
||||
|
||||
_createBinding(bindingOrType) {
|
||||
|
@ -212,7 +214,9 @@ export class ElementInjector extends TreeNode {
|
|||
*/
|
||||
|
||||
@FIELD('_proto:ProtoElementInjector')
|
||||
@FIELD('_appInjector:Injector')
|
||||
@FIELD('_lightDomAppInjector:Injector')
|
||||
@FIELD('_shadowDomAppInjector:Injector')
|
||||
@FIELD('_host:ElementInjector')
|
||||
@FIELD('_obj0:Object')
|
||||
@FIELD('_obj1:Object')
|
||||
@FIELD('_obj2:Object')
|
||||
|
@ -224,13 +228,24 @@ export class ElementInjector extends TreeNode {
|
|||
@FIELD('_obj8:Object')
|
||||
@FIELD('_obj9:Object')
|
||||
@FIELD('_view:View')
|
||||
constructor(proto:ProtoElementInjector, parent:ElementInjector, view) {
|
||||
constructor(proto:ProtoElementInjector, parent:ElementInjector, host:ElementInjector, view) {
|
||||
super(parent);
|
||||
if (isPresent(parent) && isPresent(host)) {
|
||||
throw new BaseException('Only either parent or host is allowed');
|
||||
}
|
||||
this._host = null; // needed to satisfy Dart
|
||||
if (isPresent(parent)) {
|
||||
this._host = parent._host;
|
||||
} else {
|
||||
this._host = host;
|
||||
}
|
||||
|
||||
this._proto = proto;
|
||||
this._view = view;
|
||||
|
||||
//we cannot call clearDirectives because fields won't be detected
|
||||
this._appInjector = null;
|
||||
this._lightDomAppInjector = null;
|
||||
this._shadowDomAppInjector = null;
|
||||
this._obj0 = null;
|
||||
this._obj1 = null;
|
||||
this._obj2 = null;
|
||||
|
@ -245,7 +260,9 @@ export class ElementInjector extends TreeNode {
|
|||
}
|
||||
|
||||
clearDirectives() {
|
||||
this._appInjector = null;
|
||||
this._lightDomAppInjector = null;
|
||||
this._shadowDomAppInjector = null;
|
||||
|
||||
this._obj0 = null;
|
||||
this._obj1 = null;
|
||||
this._obj2 = null;
|
||||
|
@ -259,24 +276,42 @@ export class ElementInjector extends TreeNode {
|
|||
this._constructionCounter = 0;
|
||||
}
|
||||
|
||||
instantiateDirectives(appInjector:Injector) {
|
||||
this._appInjector = appInjector;
|
||||
|
||||
instantiateDirectives(lightDomAppInjector:Injector, shadowDomAppInjector:Injector) {
|
||||
var p = this._proto;
|
||||
if (this._proto._binding0IsComponent && isBlank(shadowDomAppInjector)) {
|
||||
throw new BaseException('A shadowDomAppInjector is required as this ElementInjector contains a component');
|
||||
} else if (!this._proto._binding0IsComponent && isPresent(shadowDomAppInjector)) {
|
||||
throw new BaseException('No shadowDomAppInjector allowed as there is not component stored in this ElementInjector');
|
||||
}
|
||||
this._lightDomAppInjector = lightDomAppInjector;
|
||||
this._shadowDomAppInjector = shadowDomAppInjector;
|
||||
|
||||
if (isPresent(p._keyId0)) this._getDirectiveByKeyId(p._keyId0);
|
||||
if (isPresent(p._keyId1)) this._getDirectiveByKeyId(p._keyId1);
|
||||
if (isPresent(p._keyId2)) this._getDirectiveByKeyId(p._keyId2);;
|
||||
if (isPresent(p._keyId3)) this._getDirectiveByKeyId(p._keyId3);;
|
||||
if (isPresent(p._keyId4)) this._getDirectiveByKeyId(p._keyId4);;
|
||||
if (isPresent(p._keyId5)) this._getDirectiveByKeyId(p._keyId5);;
|
||||
if (isPresent(p._keyId6)) this._getDirectiveByKeyId(p._keyId6);;
|
||||
if (isPresent(p._keyId7)) this._getDirectiveByKeyId(p._keyId7);;
|
||||
if (isPresent(p._keyId8)) this._getDirectiveByKeyId(p._keyId8);;
|
||||
if (isPresent(p._keyId9)) this._getDirectiveByKeyId(p._keyId9);;
|
||||
if (isPresent(p._keyId2)) this._getDirectiveByKeyId(p._keyId2);
|
||||
if (isPresent(p._keyId3)) this._getDirectiveByKeyId(p._keyId3);
|
||||
if (isPresent(p._keyId4)) this._getDirectiveByKeyId(p._keyId4);
|
||||
if (isPresent(p._keyId5)) this._getDirectiveByKeyId(p._keyId5);
|
||||
if (isPresent(p._keyId6)) this._getDirectiveByKeyId(p._keyId6);
|
||||
if (isPresent(p._keyId7)) this._getDirectiveByKeyId(p._keyId7);
|
||||
if (isPresent(p._keyId8)) this._getDirectiveByKeyId(p._keyId8);
|
||||
if (isPresent(p._keyId9)) this._getDirectiveByKeyId(p._keyId9);
|
||||
}
|
||||
|
||||
get(token) {
|
||||
return this._getByKey(Key.get(token), 0);
|
||||
return this._getByKey(Key.get(token), 0, null);
|
||||
}
|
||||
|
||||
getComponent() {
|
||||
if (this._proto._binding0IsComponent) {
|
||||
return this._obj0;
|
||||
} else {
|
||||
throw new BaseException('There is not component stored in this ElementInjector');
|
||||
}
|
||||
}
|
||||
|
||||
_isComponentKey(key:Key) {
|
||||
return this._proto._binding0IsComponent && key.id === this._proto._keyId0;
|
||||
}
|
||||
|
||||
_new(binding:Binding) {
|
||||
|
@ -290,16 +325,16 @@ export class ElementInjector extends TreeNode {
|
|||
|
||||
var d0,d1,d2,d3,d4,d5,d6,d7,d8,d9;
|
||||
try {
|
||||
d0 = length > 0 ? this._getByDependency(deps[0]) : null;
|
||||
d1 = length > 1 ? this._getByDependency(deps[1]) : null;
|
||||
d2 = length > 2 ? this._getByDependency(deps[2]) : null;
|
||||
d3 = length > 3 ? this._getByDependency(deps[3]) : null;
|
||||
d4 = length > 4 ? this._getByDependency(deps[4]) : null;
|
||||
d5 = length > 5 ? this._getByDependency(deps[5]) : null;
|
||||
d6 = length > 6 ? this._getByDependency(deps[6]) : null;
|
||||
d7 = length > 7 ? this._getByDependency(deps[7]) : null;
|
||||
d8 = length > 8 ? this._getByDependency(deps[8]) : null;
|
||||
d9 = length > 9 ? this._getByDependency(deps[9]) : null;
|
||||
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;
|
||||
} catch(e) {
|
||||
if (e instanceof ProviderError) e.addKey(binding.key);
|
||||
throw e;
|
||||
|
@ -324,8 +359,8 @@ export class ElementInjector extends TreeNode {
|
|||
return obj;
|
||||
}
|
||||
|
||||
_getByDependency(dep:DirectiveDependency) {
|
||||
return this._getByKey(dep.key, dep.depth);
|
||||
_getByDependency(dep:DirectiveDependency, requestor:Key) {
|
||||
return this._getByKey(dep.key, dep.depth, requestor);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -340,7 +375,7 @@ export class ElementInjector extends TreeNode {
|
|||
*
|
||||
* Write benchmarks before doing this optimization.
|
||||
*/
|
||||
_getByKey(key:Key, depth:int) {
|
||||
_getByKey(key:Key, depth:int, requestor:Key) {
|
||||
var ei = this;
|
||||
while (ei != null && depth >= 0) {
|
||||
var specObj = ei._getSpecialObjectByKeyId(key.id);
|
||||
|
@ -352,7 +387,17 @@ export class ElementInjector extends TreeNode {
|
|||
ei = ei._parent;
|
||||
depth -= 1;
|
||||
}
|
||||
return this._appInjector.get(key);
|
||||
if (isPresent(this._host) && this._host._isComponentKey(key)) {
|
||||
return this._host.getComponent();
|
||||
} else {
|
||||
var appInjector;
|
||||
if (isPresent(requestor) && this._isComponentKey(requestor)) {
|
||||
appInjector = this._shadowDomAppInjector;
|
||||
} else {
|
||||
appInjector = this._lightDomAppInjector;
|
||||
}
|
||||
return appInjector.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
_getSpecialObjectByKeyId(keyId:int) {
|
||||
|
@ -364,6 +409,7 @@ export class ElementInjector extends TreeNode {
|
|||
|
||||
_getDirectiveByKeyId(keyId:int) {
|
||||
var p = this._proto;
|
||||
|
||||
if (p._keyId0 === keyId) {if (isBlank(this._obj0)){this._obj0 = this._new(p._binding0);} return this._obj0;}
|
||||
if (p._keyId1 === keyId) {if (isBlank(this._obj1)){this._obj1 = this._new(p._binding1);} return this._obj1;}
|
||||
if (p._keyId2 === keyId) {if (isBlank(this._obj2)){this._obj2 = this._new(p._binding2);} return this._obj2;}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import {isPresent,} from 'facade/lang';
|
||||
import {isPresent, isBlank} from 'facade/lang';
|
||||
import {ListWrapper} from 'facade/collection';
|
||||
|
||||
import {ProtoElementInjector} from '../element_injector';
|
||||
import {Key} from 'di/di';
|
||||
import {ProtoElementInjector, ComponentKeyMetaData} from '../element_injector';
|
||||
|
||||
import {CompileStep} from './compile_step';
|
||||
import {CompileElement} from './compile_element';
|
||||
|
@ -23,22 +24,23 @@ import {CompileControl} from './compile_control';
|
|||
*/
|
||||
export class ProtoElementInjectorBuilder extends CompileStep {
|
||||
// public so that we can overwrite it in tests
|
||||
internalCreateProtoElementInjector(parent, index, directives) {
|
||||
return new ProtoElementInjector(parent, index, directives);
|
||||
internalCreateProtoElementInjector(parent, index, directives, firstBindingIsComponent) {
|
||||
return new ProtoElementInjector(parent, index, directives, firstBindingIsComponent);
|
||||
}
|
||||
|
||||
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
|
||||
var inheritedProtoElementInjector = null;
|
||||
var parentProtoElementInjector = this._getParentProtoElementInjector(parent, current);
|
||||
var injectorBindings = this._collectDirectiveTypes(current);
|
||||
var injectorBindings = this._collectDirectiveBindings(current);
|
||||
// TODO: add lightDomServices as well,
|
||||
// but after the directives as we rely on that order
|
||||
// in the element_binder_builder.
|
||||
|
||||
if (injectorBindings.length > 0) {
|
||||
var protoView = current.inheritedProtoView;
|
||||
var hasComponent = isPresent(current.componentDirective);
|
||||
inheritedProtoElementInjector = this.internalCreateProtoElementInjector(
|
||||
parentProtoElementInjector, protoView.elementBinders.length, injectorBindings
|
||||
parentProtoElementInjector, protoView.elementBinders.length, injectorBindings, hasComponent
|
||||
);
|
||||
} else {
|
||||
inheritedProtoElementInjector = parentProtoElementInjector;
|
||||
|
@ -56,19 +58,19 @@ export class ProtoElementInjectorBuilder extends CompileStep {
|
|||
return parentProtoElementInjector;
|
||||
}
|
||||
|
||||
_collectDirectiveTypes(pipelineElement) {
|
||||
_collectDirectiveBindings(pipelineElement) {
|
||||
var directiveTypes = [];
|
||||
if (isPresent(pipelineElement.componentDirective)) {
|
||||
ListWrapper.push(directiveTypes, pipelineElement.componentDirective.type);
|
||||
}
|
||||
if (isPresent(pipelineElement.templateDirective)) {
|
||||
ListWrapper.push(directiveTypes, pipelineElement.templateDirective.type);
|
||||
}
|
||||
if (isPresent(pipelineElement.decoratorDirectives)) {
|
||||
for (var i=0; i<pipelineElement.decoratorDirectives.length; i++) {
|
||||
ListWrapper.push(directiveTypes, pipelineElement.decoratorDirectives[i].type);
|
||||
}
|
||||
}
|
||||
if (isPresent(pipelineElement.templateDirective)) {
|
||||
ListWrapper.push(directiveTypes, pipelineElement.templateDirective.type);
|
||||
}
|
||||
if (isPresent(pipelineElement.componentDirective)) {
|
||||
ListWrapper.push(directiveTypes, pipelineElement.componentDirective.type);
|
||||
}
|
||||
return directiveTypes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -167,13 +167,13 @@ export class ProtoView {
|
|||
static _instantiateDirectives(
|
||||
injectors:List<ElementInjectors>, appInjector:Injector) {
|
||||
for (var i = 0; i < injectors.length; ++i) {
|
||||
if (injectors[i] != null) injectors[i].instantiateDirectives(appInjector);
|
||||
if (injectors[i] != null) injectors[i].instantiateDirectives(appInjector, null);
|
||||
}
|
||||
}
|
||||
|
||||
static _createElementInjector(element, parent:ElementInjector, proto:ProtoElementInjector) {
|
||||
//TODO: vsavkin: pass element to `proto.instantiate()` once https://github.com/angular/angular/pull/98 is merged
|
||||
return proto.instantiate(parent, null);
|
||||
return proto.instantiate(parent, null, null);
|
||||
}
|
||||
|
||||
static _rootElementInjectors(injectors) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach} from 'test_lib/test_lib';
|
||||
import {isBlank, FIELD, IMPLEMENTS} from 'facade/lang';
|
||||
import {isBlank, isPresent, FIELD, IMPLEMENTS} from 'facade/lang';
|
||||
import {ListWrapper, MapWrapper, List} from 'facade/collection';
|
||||
import {ProtoElementInjector, VIEW_KEY} from 'core/compiler/element_injector';
|
||||
import {Parent, Ancestor} from 'core/annotations/visibility';
|
||||
|
@ -12,6 +12,10 @@ class DummyView {}
|
|||
class Directive {
|
||||
}
|
||||
|
||||
|
||||
class SomeOtherDirective {
|
||||
}
|
||||
|
||||
class NeedsDirective {
|
||||
@FIELD("dependency:Directive")
|
||||
constructor(dependency:Directive){
|
||||
|
@ -66,13 +70,13 @@ export function main() {
|
|||
return [lookupName(tree), children];
|
||||
}
|
||||
|
||||
function injector(bindings, appInjector = null, props = null) {
|
||||
if (isBlank(appInjector)) appInjector = new Injector([]);
|
||||
if (isBlank(props)) props = {"view" : null};
|
||||
function injector(bindings, lightDomAppInjector = null, shadowDomAppInjector = null, props = null) {
|
||||
if (isBlank(lightDomAppInjector)) lightDomAppInjector = new Injector([]);
|
||||
if (isBlank(props)) props = {"view": null};
|
||||
|
||||
var proto = new ProtoElementInjector(null, 0, bindings);
|
||||
var inj = proto.instantiate(null, props["view"]);
|
||||
inj.instantiateDirectives(appInjector);
|
||||
var proto = new ProtoElementInjector(null, 0, bindings, isPresent(shadowDomAppInjector));
|
||||
var inj = proto.instantiate(null, null, props["view"]);
|
||||
inj.instantiateDirectives(lightDomAppInjector, shadowDomAppInjector);
|
||||
return inj;
|
||||
}
|
||||
|
||||
|
@ -80,16 +84,31 @@ export function main() {
|
|||
var inj = new Injector([]);
|
||||
|
||||
var protoParent = new ProtoElementInjector(null, 0, parentBindings);
|
||||
var parent = protoParent.instantiate(null, null);
|
||||
parent.instantiateDirectives(inj);
|
||||
var parent = protoParent.instantiate(null, null, null);
|
||||
parent.instantiateDirectives(inj, null);
|
||||
|
||||
var protoChild = new ProtoElementInjector(protoParent, 1, childBindings);
|
||||
var child = protoChild.instantiate(parent, null);
|
||||
child.instantiateDirectives(inj);
|
||||
var child = protoChild.instantiate(parent, null, null);
|
||||
child.instantiateDirectives(inj, null);
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
function hostShadowInjectors(hostBindings, shadowBindings) {
|
||||
var inj = new Injector([]);
|
||||
var shadowInj = inj.createChild([]);
|
||||
|
||||
var protoParent = new ProtoElementInjector(null, 0, hostBindings, true);
|
||||
var host = protoParent.instantiate(null, null, null);
|
||||
host.instantiateDirectives(inj, shadowInj);
|
||||
|
||||
var protoChild = new ProtoElementInjector(protoParent, 0, shadowBindings, false);
|
||||
var shadow = protoChild.instantiate(null, host, null);
|
||||
shadow.instantiateDirectives(shadowInj, null);
|
||||
|
||||
return shadow;
|
||||
}
|
||||
|
||||
describe("ElementInjector", function () {
|
||||
describe("instantiate", function () {
|
||||
it("should create an element injector", function () {
|
||||
|
@ -97,9 +116,9 @@ export function main() {
|
|||
var protoChild1 = new ProtoElementInjector(protoParent, 1, []);
|
||||
var protoChild2 = new ProtoElementInjector(protoParent, 2, []);
|
||||
|
||||
var p = protoParent.instantiate(null, null);
|
||||
var c1 = protoChild1.instantiate(p, null);
|
||||
var c2 = protoChild2.instantiate(p, null);
|
||||
var p = protoParent.instantiate(null, null, null);
|
||||
var c1 = protoChild1.instantiate(p, null, null);
|
||||
var c2 = protoChild2.instantiate(p, null, null);
|
||||
|
||||
expect(humanize(p, [
|
||||
[p, 'parent'],
|
||||
|
@ -147,13 +166,47 @@ export function main() {
|
|||
expect(d.service).toEqual("service");
|
||||
});
|
||||
|
||||
it("should instantiate directives that depend on speical objects", function () {
|
||||
it("should instantiate directives that depend on special objects", function () {
|
||||
var view = new DummyView();
|
||||
var inj = injector([NeedsView], null, {"view" : view});
|
||||
var inj = injector([NeedsView], null, null, {'view':view});
|
||||
|
||||
expect(inj.get(NeedsView).view).toBe(view);
|
||||
});
|
||||
|
||||
it("should instantiate directives that depend on the containing component", function () {
|
||||
var shadow = hostShadowInjectors([Directive], [NeedsDirective]);
|
||||
|
||||
var d = shadow.get(NeedsDirective);
|
||||
expect(d).toBeAnInstanceOf(NeedsDirective);
|
||||
expect(d.dependency).toBeAnInstanceOf(Directive);
|
||||
});
|
||||
|
||||
it("should not instantiate directives that depend on other directives in the containing component's ElementInjector", () => {
|
||||
expect( () => {
|
||||
hostShadowInjectors([SomeOtherDirective, Directive], [NeedsDirective]);
|
||||
}).toThrowError('No provider for Directive! (NeedsDirective -> Directive)')
|
||||
});
|
||||
|
||||
it("should instantiate component directives that depend on app services in the shadow app injector", () => {
|
||||
var shadowAppInjector = new Injector([
|
||||
bind("service").toValue("service")
|
||||
]);
|
||||
var inj = injector([NeedsService], null, shadowAppInjector);
|
||||
|
||||
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 shadowAppInjector = new Injector([
|
||||
bind("service").toValue("service")
|
||||
]);
|
||||
expect( () => {
|
||||
injector([SomeOtherDirective, NeedsService], null, shadowAppInjector);
|
||||
}).toThrowError('No provider for service! (NeedsService -> service)');
|
||||
});
|
||||
|
||||
it("should return app services", function () {
|
||||
var appInjector = new Injector([
|
||||
bind("service").toValue("service")
|
||||
|
@ -204,7 +257,7 @@ export function main() {
|
|||
describe("special objects", function () {
|
||||
it("should return view", function () {
|
||||
var view = new DummyView();
|
||||
var inj = injector([], null, {"view" : view});
|
||||
var inj = injector([], null, null, {"view" : view});
|
||||
|
||||
expect(inj.get(View)).toEqual(view);
|
||||
});
|
||||
|
|
|
@ -41,9 +41,8 @@ export function main() {
|
|||
}), protoElementInjectorBuilder]);
|
||||
}
|
||||
|
||||
function assertProtoElementInjector(protoElementInjector, parent, index, bindings) {
|
||||
var args = protoElementInjectorBuilder.findArgsFor(protoElementInjector);
|
||||
expect(args).toEqual([parent, index, bindings]);
|
||||
function getCreationArgs(protoElementInjector) {
|
||||
return protoElementInjectorBuilder.findArgsFor(protoElementInjector);
|
||||
}
|
||||
|
||||
it('should not create a ProtoElementInjector for elements without directives', () => {
|
||||
|
@ -51,10 +50,19 @@ export function main() {
|
|||
expect(results[0].inheritedProtoElementInjector).toBe(null);
|
||||
});
|
||||
|
||||
it('should create a ProtoElementInjector for elements with directives', () => {
|
||||
var directives = [SomeDecoratorDirective, SomeTemplateDirective, SomeComponentDirective];
|
||||
it('should create a ProtoElementInjector for elements directives', () => {
|
||||
var directives = [SomeComponentDirective, SomeTemplateDirective, SomeDecoratorDirective];
|
||||
var results = createPipeline(directives).process(createElement('<div directives></div>'));
|
||||
assertProtoElementInjector(results[0].inheritedProtoElementInjector, null, 0, directives);
|
||||
var creationArgs = getCreationArgs(results[0].inheritedProtoElementInjector);
|
||||
expect(creationArgs['bindings']).toEqual(directives);
|
||||
});
|
||||
|
||||
it('should mark ProtoElementInjector for elements with component directives and use the ComponentDirective as first binding', () => {
|
||||
var directives = [SomeDecoratorDirective, SomeComponentDirective];
|
||||
var results = createPipeline(directives).process(createElement('<div directives></div>'));
|
||||
var creationArgs = getCreationArgs(results[0].inheritedProtoElementInjector);
|
||||
expect(creationArgs['firstBindingIsComponent']).toBe(true);
|
||||
expect(creationArgs['bindings']).toEqual([SomeComponentDirective, SomeDecoratorDirective]);
|
||||
});
|
||||
|
||||
it('should use the next ElementBinder index as index of the ProtoElementInjector', () => {
|
||||
|
@ -63,37 +71,36 @@ export function main() {
|
|||
ListWrapper.push(protoView.elementBinders, null);
|
||||
var directives = [SomeDecoratorDirective];
|
||||
var results = createPipeline(directives).process(createElement('<div directives></div>'));
|
||||
assertProtoElementInjector(
|
||||
results[0].inheritedProtoElementInjector, null, protoView.elementBinders.length, directives);
|
||||
var creationArgs = getCreationArgs(results[0].inheritedProtoElementInjector);
|
||||
expect(creationArgs['index']).toBe(protoView.elementBinders.length);
|
||||
});
|
||||
|
||||
it('should inherit the ProtoElementInjector down to children without directives', () => {
|
||||
var directives = [SomeDecoratorDirective, SomeTemplateDirective, SomeComponentDirective];
|
||||
var directives = [SomeDecoratorDirective];
|
||||
var results = createPipeline(directives).process(createElement('<div directives><span></span></div>'));
|
||||
assertProtoElementInjector(results[0].inheritedProtoElementInjector, null, 0, directives);
|
||||
assertProtoElementInjector(results[1].inheritedProtoElementInjector, null, 0, directives);
|
||||
expect(results[1].inheritedProtoElementInjector).toBe(results[0].inheritedProtoElementInjector);
|
||||
});
|
||||
|
||||
it('should use the ProtoElementInjector of the parent element as parent', () => {
|
||||
var el = createElement('<div directives><span><a directives></a></span></div>');
|
||||
var directives = [SomeDecoratorDirective, SomeTemplateDirective, SomeComponentDirective];
|
||||
var directives = [SomeDecoratorDirective];
|
||||
var results = createPipeline(directives).process(el);
|
||||
assertProtoElementInjector(results[2].inheritedProtoElementInjector,
|
||||
results[0].inheritedProtoElementInjector, 0, directives);
|
||||
expect(results[2].inheritedProtoElementInjector.parent).toBe(
|
||||
results[0].inheritedProtoElementInjector);
|
||||
});
|
||||
|
||||
it('should use a null parent for viewRoots', () => {
|
||||
var el = createElement('<div directives><span viewroot directives></span></div>');
|
||||
var directives = [SomeDecoratorDirective, SomeTemplateDirective, SomeComponentDirective];
|
||||
var directives = [SomeDecoratorDirective];
|
||||
var results = createPipeline(directives).process(el);
|
||||
assertProtoElementInjector(results[1].inheritedProtoElementInjector, null, 0, directives);
|
||||
expect(results[1].inheritedProtoElementInjector.parent).toBe(null);
|
||||
});
|
||||
|
||||
it('should use a null parent if there is an intermediate viewRoot', () => {
|
||||
var el = createElement('<div directives><span viewroot><a directives></a></span></div>');
|
||||
var directives = [SomeDecoratorDirective, SomeTemplateDirective, SomeComponentDirective];
|
||||
var directives = [SomeDecoratorDirective];
|
||||
var results = createPipeline(directives).process(el);
|
||||
assertProtoElementInjector(results[2].inheritedProtoElementInjector, null, 0, directives);
|
||||
expect(results[2].inheritedProtoElementInjector.parent).toBe(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -111,10 +118,10 @@ class TestableProtoElementInjectorBuilder extends ProtoElementInjectorBuilder {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
internalCreateProtoElementInjector(parent, index, directives) {
|
||||
var result = new ProtoElementInjector(parent, index, directives);
|
||||
internalCreateProtoElementInjector(parent, index, bindings, firstBindingIsComponent) {
|
||||
var result = new ProtoElementInjector(parent, index, bindings, firstBindingIsComponent);
|
||||
ListWrapper.push(this.debugObjects, result);
|
||||
ListWrapper.push(this.debugObjects, [parent, index, directives]);
|
||||
ListWrapper.push(this.debugObjects, {'parent': parent, 'index': index, 'bindings': bindings, 'firstBindingIsComponent': firstBindingIsComponent});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -128,10 +135,14 @@ class MockStep extends CompileStep {
|
|||
}
|
||||
}
|
||||
|
||||
class SomeComponentService {}
|
||||
|
||||
@Template()
|
||||
class SomeTemplateDirective {}
|
||||
|
||||
@Component()
|
||||
@Component({
|
||||
componentServices: [SomeComponentService]
|
||||
})
|
||||
class SomeComponentDirective {}
|
||||
|
||||
@Decorator()
|
||||
|
|
Loading…
Reference in New Issue