feat(di): removed publishAs

BREAKING CHANGES

Removes the publishAs property from the Component annotation.
This commit is contained in:
vsavkin 2015-05-15 15:54:54 -07:00
parent 155b1e2b35
commit 3a53f67911
4 changed files with 2 additions and 238 deletions

View File

@ -845,41 +845,6 @@ export class Component extends Directive {
*/
injectables:List;
// TODO(naomib): needs documentation
/**
* Dependency injection tokens that this component publishes _itself_ to its
* children in its view via the application injector.
*
* ## Examples
*
* Imagine you have parent component that implements the [RpcService]
* interface. It can pose as [RpcService] to its children. Child components
* do not need to know about this fact. They only need to declare their
* dependency on [RpcService] without knowing exactly how it is provided.
*
* ```
* @Component({
* selector: 'parent',
* publishAs: [RpcService]
* })
* @View({
* template: '<child></child>',
* directives: [Child]
* })
* class Parent implements RpcService {
* }
*
* @Component({
* selector: 'child'
* })
* class Child {
* // Just asks for RpcService; doesn't know that it's Parent.
* constructor(RpcService rpc);
* }
* ```
*/
publishAs:List;
@CONST()
constructor({
selector,
@ -892,8 +857,7 @@ export class Component extends Directive {
injectables,
lifecycle,
changeDetection = DEFAULT,
compileChildren = true,
publishAs
compileChildren = true
}:{
selector:string,
properties:Object,
@ -905,8 +869,7 @@ export class Component extends Directive {
injectables:List,
lifecycle:List,
changeDetection:string,
compileChildren:boolean,
publishAs:List
compileChildren:boolean
}={})
{
super({
@ -923,7 +886,6 @@ export class Component extends Directive {
this.changeDetection = changeDetection;
this.injectables = injectables;
this.publishAs = publishAs;
}
}

View File

@ -227,18 +227,12 @@ export class DirectiveDependency extends Dependency {
export class DirectiveBinding extends ResolvedBinding {
resolvedInjectables:List<ResolvedBinding>;
metadata: DirectiveMetadata;
publishAs: List<Type>;
constructor(key:Key, factory:Function, dependencies:List, providedAsPromise:boolean,
resolvedInjectables:List<ResolvedBinding>, metadata:DirectiveMetadata, annotation: Directive) {
super(key, factory, dependencies, providedAsPromise);
this.resolvedInjectables = resolvedInjectables;
this.metadata = metadata;
if (annotation instanceof Component) {
this.publishAs = annotation.publishAs;
} else {
this.publishAs = null;
}
}
get callOnDestroy() {
@ -678,20 +672,6 @@ export class ElementInjector extends TreeNode {
var p = this._proto;
if (isPresent(p._keyId0)) this._getDirectiveByKeyId(p._keyId0);
if (isPresent(shadowDomAppInjector)) {
var publishAs = this._proto._binding0.publishAs;
if (isPresent(publishAs) && publishAs.length > 0) {
// If there's a component directive on this element injector, then
// 0-th key must contain the directive itself.
// TODO(yjbanov): need to make injector creation faster:
// - remove flattening of bindings array
// - precalc token key
this._shadowDomAppInjector = shadowDomAppInjector.resolveAndCreateChild(
ListWrapper.map(publishAs, (token) => {
return bind(token).toValue(this.getComponent());
}));
}
}
if (isPresent(p._keyId1)) this._getDirectiveByKeyId(p._keyId1);
if (isPresent(p._keyId2)) this._getDirectiveByKeyId(p._keyId2);
if (isPresent(p._keyId3)) this._getDirectiveByKeyId(p._keyId3);

View File

@ -195,30 +195,6 @@ class TestNode extends TreeNode {
}
}
// TypeScript erases interfaces, so it has to be a class
class ParentInterface {}
class ParentComponent extends ParentInterface {
}
class AppDependency {
parent:ParentInterface;
constructor(p:ParentInterface) {
this.parent = p;
}
}
class ChildComponent {
parent:ParentInterface;
appDependency:AppDependency;
constructor(p:ParentInterface, a:AppDependency) {
this.parent = p;
this.appDependency = a;
}
}
export function main() {
var defaultPreBuiltObjects = new PreBuiltObjects(null, null, null);
var appInjector = Injector.resolveAndCreate([]);
@ -647,31 +623,6 @@ export function main() {
inj.clearDirectives();
expect(destroy.onDestroyCounter).toBe(1);
});
it("should publish component to its children via app injector when requested", function() {
var parentDirective = new Component({
selector: 'parent',
publishAs: [ParentInterface]
});
var parentBinding = DirectiveBinding.createFromType(ParentComponent, parentDirective);
var childDirective = new Component({
selector: 'child',
injectables: [AppDependency]
});
var childBinding = DirectiveBinding.createFromType(ChildComponent, childDirective);
var child = hostShadowInjectors([parentBinding], [childBinding], true, true);
var d = child.get(ChildComponent);
// Verify that the child component can inject parent via interface binding
expect(d).toBeAnInstanceOf(ChildComponent);
expect(d.parent).toBeAnInstanceOf(ParentComponent);
// Verify that the binding is available down the dependency tree
expect(d.appDependency.parent).toBeAnInstanceOf(ParentComponent);
expect(d.parent).toBe(d.appDependency.parent);
});
});
describe("dynamicallyCreateComponent", () => {

View File

@ -986,71 +986,6 @@ export function main() {
}));
}
});
describe('dependency injection', () => {
it('should publish parent component to shadow DOM via publishAs',
inject([TestBed, AsyncTestCompleter, Compiler], (tb, async, compiler) => {
tb.overrideView(MyComp, new View({
template: `<parent></parent>`,
directives: [ParentComponent]
}));
tb.createView(MyComp).then((view) => {
view.detectChanges();
expect(view.rootNodes).toHaveText(
'Parent,Parent');
async.done();
});
}));
it('should override parent bindings via publishAs',
inject([TestBed, AsyncTestCompleter, Compiler], (tb, async, compiler) => {
tb.overrideView(MyComp, new View({
template: `<recursive-parent></recursive-parent>`,
directives: [RecursiveParentComponent]
}));
tb.createView(MyComp).then((view) => {
view.detectChanges();
expect(view.rootNodes).toHaveText(
'ParentInterface,RecursiveParent,RecursiveParent');
async.done();
});
}));
// [DynamicComponentLoader] already supports providing a custom
// injector as an argument to `loadIntoExistingLocation`, which should
// be used instead of `publishAs`.
//
// Conceptually dynamically loaded components are loaded _instead_ of
// the dynamic component itself. The dynamic component does not own the
// shadow DOM. It's the loaded component that creates that shadow DOM.
it('should not publish into dynamically instantiated components via publishAs',
inject([TestBed, AsyncTestCompleter, Compiler], (tb, async, compiler) => {
tb.overrideView(MyComp, new View({
template: `<dynamic-parent #cmp></dynamic-parent>`,
directives: [DynamicParentComponent]
}));
tb.createView(MyComp).then((view) => {
view.detectChanges();
var comp = view.rawView.locals.get("cmp");
PromiseWrapper.then(comp.done,
(value) => {
throw new BaseException(`Expected to throw error, but got value ${value}`);
},
(err) => {
expect(err.message)
.toEqual('No provider for ParentInterface! (ChildComponent -> ParentInterface)');
async.done();
}
);
});
}));
});
});
}
@ -1479,70 +1414,6 @@ class NeedsPublicApi {
}
}
class ParentInterface {
message:String;
constructor() {
this.message = 'ParentInterface';
}
}
@Component({
selector: 'parent',
publishAs: [ParentInterface]
})
@View({
template: `<child></child>`,
directives: [ChildComponent]
})
class ParentComponent extends ParentInterface {
message:String;
constructor() {
super();
this.message = 'Parent';
}
}
@Component({
injectables: [ParentInterface],
selector: 'recursive-parent',
publishAs: [ParentInterface]
})
@View({
template: `{{parentService.message}},<child></child>`,
directives: [ChildComponent]
})
class RecursiveParentComponent extends ParentInterface {
parentService:ParentInterface;
message:String;
constructor(parentService:ParentInterface) {
super();
this.message = 'RecursiveParent';
this.parentService = parentService;
}
}
@Component({
selector: 'dynamic-parent',
publishAs: [ParentInterface]
})
class DynamicParentComponent extends ParentInterface {
message:String;
done;
constructor(loader:DynamicComponentLoader, location:ElementRef) {
super();
this.message = 'DynamicParent';
this.done = loader.loadIntoExistingLocation(ChildComponent, location);
}
}
class AppDependency {
parent:ParentInterface;
constructor(p:ParentInterface) {
this.parent = p;
}
}
@Component({
selector: 'child',
injectables: [AppDependency]