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:
Tobias Bosch 2014-11-12 11:17:46 -08:00
parent c68e78075a
commit 7308a3acc7
8 changed files with 207 additions and 95 deletions

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;}

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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);
});

View File

@ -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()