refactor(di): removed @Parent

BREAKING CHANGE
    The @Parent annotation has been removed. Use @Ancestor instead.
    @Parent was used to enforce a particular DOM structure (e.g., a pane component is a direct child of the tabs component).
    DI is not the right mechanism to do it. We should enforce it using schema instead.
This commit is contained in:
vsavkin
2015-07-13 15:57:06 -07:00
parent a472eacc07
commit 6f4a39c337
16 changed files with 269 additions and 256 deletions

View File

@ -40,7 +40,7 @@ import {
Directive,
LifecycleEvent
} from 'angular2/annotations';
import {bind, Injector, Binding, Optional, Inject, Injectable, Self, Parent, Ancestor, Unbounded, InjectMetadata, ParentMetadata} from 'angular2/di';
import {bind, Injector, Binding, Optional, Inject, Injectable, Self, Ancestor, Unbounded, InjectMetadata, AncestorMetadata} from 'angular2/di';
import {AppProtoView, AppView} from 'angular2/src/core/compiler/view';
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
import {TemplateRef} from 'angular2/src/core/compiler/template_ref';
@ -102,18 +102,6 @@ class OptionallyNeedsDirective {
constructor(@Self() @Optional() dependency: SimpleDirective) { this.dependency = dependency; }
}
@Injectable()
class NeedsDirectiveFromParent {
dependency: SimpleDirective;
constructor(@Parent() dependency: SimpleDirective) { this.dependency = dependency; }
}
@Injectable()
class NeedsDirectiveFromParentOrSelf {
dependency: SimpleDirective;
constructor(@Parent({self: true}) dependency: SimpleDirective) { this.dependency = dependency; }
}
@Injectable()
class NeedsDirectiveFromAncestor {
dependency: SimpleDirective;
@ -609,7 +597,7 @@ export function main() {
bind('injectable2')
.toFactory(
(val) => `${val}-injectable2`,
[[new InjectMetadata('injectable1'), new ParentMetadata()]])
[[new InjectMetadata('injectable1'), new AncestorMetadata()]])
]
}))]);
expect(childInj.get('injectable2')).toEqual('injectable1-injectable2');
@ -775,31 +763,6 @@ export function main() {
expect(inj.get(NeedsTemplateRef).templateRef).toEqual(templateRef);
});
it("should get directives from parent", () => {
var child = parentChildInjectors(ListWrapper.concat([SimpleDirective], extraBindings),
[NeedsDirectiveFromParent]);
var d = child.get(NeedsDirectiveFromParent);
expect(d).toBeAnInstanceOf(NeedsDirectiveFromParent);
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
});
it("should not return parent's directives on self by default", () => {
expect(() => {
injector(ListWrapper.concat([SimpleDirective, NeedsDirectiveFromParent], extraBindings));
}).toThrowError(containsRegexp(`No provider for ${stringify(SimpleDirective) }`));
});
it("should return parent's directives on self when explicitly specified", () => {
var inj = injector(ListWrapper.concat([SimpleDirective, NeedsDirectiveFromParentOrSelf], extraBindings));
var d = inj.get(NeedsDirectiveFromParentOrSelf);
expect(d).toBeAnInstanceOf(NeedsDirectiveFromParentOrSelf);
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
});
it("should get directives from ancestor", () => {
var child = parentChildInjectors(ListWrapper.concat([SimpleDirective], extraBindings),
[NeedsDirectiveFromAncestor]);
@ -822,9 +785,9 @@ export function main() {
});
it("should throw when a dependency cannot be resolved", () => {
expect(() => injector(ListWrapper.concat([NeedsDirectiveFromParent], extraBindings)))
expect(() => injector(ListWrapper.concat([NeedsDirectiveFromAncestor], extraBindings)))
.toThrowError(containsRegexp(
`No provider for ${stringify(SimpleDirective) }! (${stringify(NeedsDirectiveFromParent) } -> ${stringify(SimpleDirective) })`));
`No provider for ${stringify(SimpleDirective) }! (${stringify(NeedsDirectiveFromAncestor) } -> ${stringify(SimpleDirective) })`));
});
it("should inject null when an optional dependency cannot be resolved", () => {
@ -853,30 +816,30 @@ export function main() {
.toThrowError(`Index ${firsIndexOut} is out-of-bounds.`);
});
it("should instantiate directives that depend on the containing component", () => {
var directiveBinding =
DirectiveBinding.createFromType(SimpleDirective, new dirAnn.Component());
var shadow = hostShadowInjectors(ListWrapper.concat([directiveBinding], extraBindings),
[NeedsDirective]);
it("should instantiate directives that depend on the containing component", () => {
var directiveBinding =
DirectiveBinding.createFromType(SimpleDirective, new dirAnn.Component());
var shadow = hostShadowInjectors(ListWrapper.concat([directiveBinding], extraBindings),
[NeedsDirectiveFromAncestor]);
var d = shadow.get(NeedsDirective);
expect(d).toBeAnInstanceOf(NeedsDirective);
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
});
var d = shadow.get(NeedsDirectiveFromAncestor);
expect(d).toBeAnInstanceOf(NeedsDirectiveFromAncestor);
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
});
it("should not instantiate directives that depend on other directives in the containing component's ElementInjector",
() => {
var directiveBinding =
DirectiveBinding.createFromType(SomeOtherDirective, new dirAnn.Component());
expect(() =>
{
hostShadowInjectors(
ListWrapper.concat([directiveBinding, SimpleDirective], extraBindings),
[NeedsDirective]);
})
.toThrowError(containsRegexp(
`No provider for ${stringify(SimpleDirective) }! (${stringify(NeedsDirective) } -> ${stringify(SimpleDirective) })`));
});
it("should not instantiate directives that depend on other directives in the containing component's ElementInjector",
() => {
var directiveBinding =
DirectiveBinding.createFromType(SomeOtherDirective, new dirAnn.Component());
expect(() =>
{
hostShadowInjectors(
ListWrapper.concat([directiveBinding, SimpleDirective], extraBindings),
[NeedsDirective]);
})
.toThrowError(containsRegexp(
`No provider for ${stringify(SimpleDirective) }! (${stringify(NeedsDirective) } -> ${stringify(SimpleDirective) })`));
});
});
describe("lifecycle", () => {

View File

@ -42,7 +42,6 @@ import {
forwardRef,
OpaqueToken,
Inject,
Parent,
Ancestor,
Unbounded,
UnboundedMetadata
@ -423,8 +422,8 @@ export function main() {
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new viewAnn.View({
template:
'<some-directive><toolbar><template toolbarpart var-toolbar-prop="toolbarProp">{{ctxProp}},{{toolbarProp}},<cmp-with-parent></cmp-with-parent></template></toolbar></some-directive>',
directives: [SomeDirective, CompWithParent, ToolbarComponent, ToolbarPart]
'<some-directive><toolbar><template toolbarpart var-toolbar-prop="toolbarProp">{{ctxProp}},{{toolbarProp}},<cmp-with-ancestor></cmp-with-ancestor></template></toolbar></some-directive>',
directives: [SomeDirective, CompWithAncestor, ToolbarComponent, ToolbarPart]
}))
.createAsync(MyComp)
.then((rootTC) => {
@ -433,7 +432,7 @@ export function main() {
expect(rootTC.nativeElement)
.toHaveText(
'TOOLBAR(From myComp,From toolbar,Component with an injected parent)');
'TOOLBAR(From myComp,From toolbar,Component with an injected ancestor)');
async.done();
});
@ -663,25 +662,6 @@ export function main() {
})}));
});
it('should create a component that injects a @Parent',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new viewAnn.View({
template:
'<some-directive><cmp-with-parent #child></cmp-with-parent></some-directive>',
directives: [SomeDirective, CompWithParent]
}))
.createAsync(MyComp)
.then((rootTC) => {
var childComponent = rootTC.componentViewChildren[0].getLocal('child');
expect(childComponent.myParent).toBeAnInstanceOf(SomeDirective);
async.done();
})}));
it('should create a component that injects an @Ancestor',
inject([TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async) => {
@ -1497,14 +1477,6 @@ class SomeDirective {
class SomeDirectiveMissingAnnotation {}
@Component({selector: 'cmp-with-parent'})
@View({template: '<p>Component with an injected parent</p>', directives: [SomeDirective]})
@Injectable()
class CompWithParent {
myParent: SomeDirective;
constructor(@Parent() someComp: SomeDirective) { this.myParent = someComp; }
}
@Component({selector: 'cmp-with-ancestor'})
@View({template: '<p>Component with an injected ancestor</p>', directives: [SomeDirective]})
@Injectable()
@ -1673,7 +1645,7 @@ class PrivateImpl extends PublicApi {
@Directive({selector: '[needs-public-api]'})
@Injectable()
class NeedsPublicApi {
constructor(@Parent() api: PublicApi) { expect(api instanceof PrivateImpl).toBe(true); }
constructor(@Ancestor() api: PublicApi) { expect(api instanceof PrivateImpl).toBe(true); }
}
@Directive({selector: '[toolbarpart]'})