Skip to content

Commit 1a0da11

Browse files
committed
feat(di): components can self-publish via publishAs
1 parent abc8878 commit 1a0da11

File tree

6 files changed

+366
-87
lines changed

6 files changed

+366
-87
lines changed

modules/angular2/src/core/annotations_impl/annotations.js

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,41 @@ export class Component extends Directive {
815815
*/
816816
injectables:List;
817817

818+
// TODO(naomib): needs documentation
819+
/**
820+
* Dependency injection tokens that this component publishes _itself_ to its
821+
* children in its view via the application injector.
822+
*
823+
* ## Examples
824+
*
825+
* Imagine you have parent component that implements the [RpcService]
826+
* interface. It can pose as [RpcService] to its children. Child components
827+
* do not need to know about this fact. They only need to declare their
828+
* dependency on [RpcService] without knowing exactly how it is provided.
829+
*
830+
* ```
831+
* @Component({
832+
* selector: 'parent',
833+
* publishAs: [RpcService]
834+
* })
835+
* @View({
836+
* template: '<child></child>',
837+
* directives: [Child]
838+
* })
839+
* class Parent implements RpcService {
840+
* }
841+
*
842+
* @Component({
843+
* selector: 'child'
844+
* })
845+
* class Child {
846+
* // Just asks for RpcService; doesn't know that it's Parent.
847+
* constructor(RpcService rpc);
848+
* }
849+
* ```
850+
*/
851+
publishAs:List;
852+
818853
@CONST()
819854
constructor({
820855
selector,
@@ -827,6 +862,7 @@ export class Component extends Directive {
827862
lifecycle,
828863
changeDetection = DEFAULT,
829864
compileChildren = true,
865+
publishAs
830866
}:{
831867
selector:string,
832868
properties:Object,
@@ -837,7 +873,8 @@ export class Component extends Directive {
837873
injectables:List,
838874
lifecycle:List,
839875
changeDetection:string,
840-
compileChildren:boolean
876+
compileChildren:boolean,
877+
publishAs:List
841878
}={})
842879
{
843880
super({
@@ -853,6 +890,7 @@ export class Component extends Directive {
853890

854891
this.changeDetection = changeDetection;
855892
this.injectables = injectables;
893+
this.publishAs = publishAs;
856894
}
857895
}
858896

modules/angular2/src/core/compiler/element_injector.js

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ export class ElementInjector extends TreeNode {
506506
_query0: QueryRef;
507507
_query1: QueryRef;
508508
_query2: QueryRef;
509+
509510
constructor(proto:ProtoElementInjector, parent:ElementInjector) {
510511
super(parent);
511512
this._proto = proto;
@@ -568,7 +569,14 @@ export class ElementInjector extends TreeNode {
568569
this._constructionCounter = 0;
569570
}
570571

571-
instantiateDirectives(lightDomAppInjector:Injector, host:ElementInjector, shadowDomAppInjector:Injector, preBuiltObjects:PreBuiltObjects) {
572+
instantiateDirectives(
573+
lightDomAppInjector:Injector,
574+
host:ElementInjector,
575+
preBuiltObjects:PreBuiltObjects) {
576+
var shadowDomAppInjector = null;
577+
if (this._proto._binding0IsComponent) {
578+
shadowDomAppInjector = this._createShadowDomAppInjector(this._proto._binding0, lightDomAppInjector);
579+
}
572580
this._host = host;
573581
this._checkShadowDomAppInjector(shadowDomAppInjector);
574582

@@ -578,6 +586,21 @@ export class ElementInjector extends TreeNode {
578586

579587
var p = this._proto;
580588
if (isPresent(p._keyId0)) this._getDirectiveByKeyId(p._keyId0);
589+
if (isPresent(shadowDomAppInjector)) {
590+
var componentAnnotation:Component = this._proto._binding0.annotation;
591+
var publishAs = componentAnnotation.publishAs;
592+
if (isPresent(publishAs) && publishAs.length > 0) {
593+
// If there's a component directive on this element injector, then
594+
// 0-th key must contain the directive itself.
595+
// TODO(yjbanov): need to make injector creation faster:
596+
// - remove flattening of bindings array
597+
// - precalc token key
598+
this._shadowDomAppInjector = shadowDomAppInjector.resolveAndCreateChild(
599+
ListWrapper.map(publishAs, (token) => {
600+
return bind(token).toValue(this.getComponent());
601+
}));
602+
}
603+
}
581604
if (isPresent(p._keyId1)) this._getDirectiveByKeyId(p._keyId1);
582605
if (isPresent(p._keyId2)) this._getDirectiveByKeyId(p._keyId2);
583606
if (isPresent(p._keyId3)) this._getDirectiveByKeyId(p._keyId3);
@@ -589,9 +612,22 @@ export class ElementInjector extends TreeNode {
589612
if (isPresent(p._keyId9)) this._getDirectiveByKeyId(p._keyId9);
590613
}
591614

592-
dynamicallyCreateComponent(directiveBinding, injector:Injector) {
593-
this._shadowDomAppInjector = injector;
594-
this._dynamicallyCreatedComponentBinding = directiveBinding;
615+
_createShadowDomAppInjector(componentDirective:DirectiveBinding, appInjector:Injector) {
616+
var shadowDomAppInjector = null;
617+
618+
// shadowDomAppInjector
619+
var injectables = componentDirective.resolvedInjectables;
620+
if (isPresent(injectables)) {
621+
shadowDomAppInjector = appInjector.createChildFromResolved(injectables);
622+
} else {
623+
shadowDomAppInjector = appInjector;
624+
}
625+
return shadowDomAppInjector;
626+
}
627+
628+
dynamicallyCreateComponent(componentDirective:DirectiveBinding, parentInjector:Injector) {
629+
this._shadowDomAppInjector = this._createShadowDomAppInjector(componentDirective, parentInjector);
630+
this._dynamicallyCreatedComponentBinding = componentDirective;
595631
this._dynamicallyCreatedComponent = this._new(this._dynamicallyCreatedComponentBinding);
596632
return this._dynamicallyCreatedComponent;
597633
}

modules/angular2/src/core/compiler/view_manager_utils.js

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -163,21 +163,7 @@ export class AppViewManagerUtils {
163163
}
164164
var annotation = this._metadataReader.read(componentBinding.token).annotation;
165165
var componentDirective = eli.DirectiveBinding.createFromBinding(componentBinding, annotation);
166-
var shadowDomAppInjector = this._createShadowDomAppInjector(componentDirective, injector);
167-
elementInjector.dynamicallyCreateComponent(componentDirective, shadowDomAppInjector);
168-
}
169-
170-
_createShadowDomAppInjector(componentDirective, appInjector) {
171-
var shadowDomAppInjector = null;
172-
173-
// shadowDomAppInjector
174-
var injectables = componentDirective.resolvedInjectables;
175-
if (isPresent(injectables)) {
176-
shadowDomAppInjector = appInjector.createChildFromResolved(injectables);
177-
} else {
178-
shadowDomAppInjector = appInjector;
179-
}
180-
return shadowDomAppInjector;
166+
elementInjector.dynamicallyCreateComponent(componentDirective, injector);
181167
}
182168

183169
_hydrateView(view:viewModule.AppView, appInjector:Injector, hostElementInjector:eli.ElementInjector, context: Object, parentLocals:Locals) {
@@ -194,14 +180,7 @@ export class AppViewManagerUtils {
194180
for (var i = 0; i < binders.length; ++i) {
195181
var elementInjector = view.elementInjectors[i];
196182
if (isPresent(elementInjector)) {
197-
var componentDirective = view.proto.elementBinders[i].componentDirective;
198-
var shadowDomAppInjector = null;
199-
if (isPresent(componentDirective)) {
200-
shadowDomAppInjector = this._createShadowDomAppInjector(componentDirective, appInjector);
201-
} else {
202-
shadowDomAppInjector = null;
203-
}
204-
elementInjector.instantiateDirectives(appInjector, hostElementInjector, shadowDomAppInjector, view.preBuiltObjects[i]);
183+
elementInjector.instantiateDirectives(appInjector, hostElementInjector, view.preBuiltObjects[i]);
205184
this._setUpEventEmitters(view, elementInjector, i);
206185

207186
// The exporting of $implicit is a special case. Since multiple elements will all export

0 commit comments

Comments
 (0)