refactor(compiler): remove Viewport directives, use Decorator instead

BREAKING_CHANGE:
- The special type of `Viewport` directives is removed
  in favor of a more general `Decorator` directive
- `ViewContainerRef` now no more has a default `ProtoViewRef`
  but requires an explicit one when creating views.

Closes #1536
This commit is contained in:
Tobias Bosch
2015-04-29 15:07:55 -07:00
parent fb67e37339
commit 3aac2fefd7
35 changed files with 280 additions and 366 deletions
+4 -16
View File
@@ -21,7 +21,7 @@ import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {AppProtoView} from 'angular2/src/core/compiler/view';
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {Component, DynamicComponent, Viewport, Decorator} from 'angular2/src/core/annotations_impl/annotations';
import {Component, DynamicComponent, Decorator} from 'angular2/src/core/annotations_impl/annotations';
import {Attribute} from 'angular2/src/core/annotations_impl/di';
import {View} from 'angular2/src/core/annotations_impl/view';
import {internalProtoView} from 'angular2/src/core/compiler/view_ref';
@@ -150,13 +150,6 @@ export function main() {
});
}));
it('should fill directive.type for viewport directives', inject([AsyncTestCompleter], (async) => {
captureDirective(SomeViewportDirective).then( (renderDir) => {
expect(renderDir.type).toEqual(renderApi.DirectiveMetadata.VIEWPORT_TYPE);
async.done();
});
}));
it('should fill directive.type for decorator directives', inject([AsyncTestCompleter], (async) => {
captureDirective(SomeDecoratorDirective).then( (renderDir) => {
expect(renderDir.type).toEqual(renderApi.DirectiveMetadata.DECORATOR_TYPE);
@@ -297,7 +290,7 @@ export function main() {
});
}));
it('should load nested components in viewport', inject([AsyncTestCompleter], (async) => {
it('should load nested components in viewcontainers', inject([AsyncTestCompleter], (async) => {
tplResolver.setView(MainComponent, new View({template: '<div></div>'}));
tplResolver.setView(NestedComponent, new View({template: '<div></div>'}));
var mainProtoView = createProtoView([
@@ -451,16 +444,14 @@ function createComponentElementBinder(reader, type) {
var binding = createDirectiveBinding(reader, type);
return new ElementBinder(
0, null, 0,
null, binding,
null
null, binding
);
}
function createViewportElementBinder(nestedProtoView) {
var elBinder = new ElementBinder(
0, null, 0,
null, null,
null
null, null
);
elBinder.nestedProtoView = nestedProtoView;
return elBinder;
@@ -502,9 +493,6 @@ class RecursiveComponent {}
@DynamicComponent()
class SomeDynamicComponentDirective {}
@Viewport()
class SomeViewportDirective {}
@Decorator()
class SomeDecoratorDirective {}
@@ -2,7 +2,7 @@ import {isPresent} from 'angular2/src/facade/lang';
import {ListWrapper} from 'angular2/src/facade/collection';
import {ddescribe, describe, it, iit, expect, beforeEach} from 'angular2/test_lib';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {Decorator, Component, Viewport} from 'angular2/src/core/annotations_impl/annotations';
import {Decorator, Component} from 'angular2/src/core/annotations_impl/annotations';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {Injectable, Injector} from 'angular2/di';
@@ -15,9 +15,6 @@ class SomeDecorator {}
@Component({selector: 'someComponent', injectables: [SomeInjectable]})
class SomeComponent {}
@Viewport({selector: 'someViewport'})
class SomeViewport {}
class SomeDirectiveWithoutAnnotation {
}
@@ -35,12 +32,6 @@ export function main() {
new DirectiveMetadata(SomeDecorator, new Decorator({selector: 'someDecorator'}), null));
});
it('should read out the Viewport annotation', () => {
var directiveMetadata = reader.read(SomeViewport);
expect(directiveMetadata).toEqual(
new DirectiveMetadata(SomeViewport, new Viewport({selector: 'someViewport'}), null));
});
it('should read out the Component annotation', () => {
var m = reader.read(SomeComponent);
// For some reason `toEqual` fails to compare ResolvedBinding objects.
@@ -16,7 +16,7 @@ import {
import {TestBed} from 'angular2/src/test_lib/test_bed';
import {Decorator, Component, Viewport, DynamicComponent} from 'angular2/src/core/annotations_impl/annotations';
import {Decorator, Component, DynamicComponent} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view';
import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader';
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
@@ -61,7 +61,7 @@ export function main() {
});
}));
it('should allow to destroy and create them via viewport directives',
it('should allow to destroy and create them via viewcontainer directives',
inject([TestBed, AsyncTestCompleter], (tb, async) => {
tb.overrideView(MyComp, new View({
template: '<div><dynamic-comp #dynamic template="if: ctxBoolProp"></dynamic-comp></div>',
@@ -705,6 +705,12 @@ export function main() {
expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView));
});
it("should throw if there is no ProtoViewRef", function () {
expect(
() => injector([NeedsProtoViewRef])
).toThrowError('No provider for ProtoViewRef! (NeedsProtoViewRef -> ProtoViewRef)');
});
});
describe('directive queries', () => {
+8 -7
View File
@@ -24,7 +24,7 @@ import {Injector, bind} from 'angular2/di';
import {PipeRegistry, defaultPipeRegistry,
ChangeDetection, DynamicChangeDetection, Pipe, ChangeDetectorRef, ON_PUSH} from 'angular2/change_detection';
import {Decorator, Component, Viewport, DynamicComponent} from 'angular2/src/core/annotations_impl/annotations';
import {Decorator, Component, DynamicComponent} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view';
import {Parent, Ancestor} from 'angular2/src/core/annotations_impl/visibility';
import {Attribute} from 'angular2/src/core/annotations_impl/di';
@@ -32,6 +32,7 @@ import {Attribute} from 'angular2/src/core/annotations_impl/di';
import {If} from 'angular2/src/directives/if';
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
import {ProtoViewRef} from 'angular2/src/core/compiler/view_ref';
import {Compiler} from 'angular2/src/core/compiler/compiler';
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
@@ -522,7 +523,7 @@ export function main() {
})
}));
it('should create a component that injects an @Ancestor through viewport directive', inject([TestBed, AsyncTestCompleter], (tb, async) => {
it('should create a component that injects an @Ancestor through viewcontainer directive', inject([TestBed, AsyncTestCompleter], (tb, async) => {
tb.overrideView(MyComp, new View({
template: `
<some-directive>
@@ -865,7 +866,7 @@ class DynamicViewport {
var myService = new MyService();
myService.greeting = 'dynamic greet';
this.done = compiler.compileInHost(ChildCompUsingService).then( (hostPv) => {
vc.create(0, hostPv, inj.createChildFromResolved(Injector.resolve([bind(MyService).toValue(myService)])))
vc.create(hostPv, 0, inj.createChildFromResolved(Injector.resolve([bind(MyService).toValue(myService)])))
});
}
}
@@ -1037,13 +1038,13 @@ class ChildComp2 {
}
}
@Viewport({
@Decorator({
selector: '[some-viewport]'
})
class SomeViewport {
constructor(container: ViewContainerRef) {
container.create().setLocal('some-tmpl', 'hello');
container.create().setLocal('some-tmpl', 'again');
constructor(container: ViewContainerRef, protoView:ProtoViewRef) {
container.create(protoView).setLocal('some-tmpl', 'hello');
container.create(protoView).setLocal('some-tmpl', 'again');
}
}
@@ -44,8 +44,8 @@ export function main() {
return new AppView(null, createProtoView(), MapWrapper.create());
}
function createViewContainer(defaultProtoView = null) {
return new ViewContainerRef(viewManager, location, defaultProtoView);
function createViewContainer() {
return new ViewContainerRef(viewManager, location);
}
beforeEach( () => {
+2 -2
View File
@@ -60,12 +60,12 @@ export function main() {
}
function createEmptyElBinder() {
return new ElementBinder(0, null, 0, null, null, null);
return new ElementBinder(0, null, 0, null, null);
}
function createComponentElBinder(nestedProtoView = null) {
var binding = createDirectiveBinding(SomeComponent);
var binder = new ElementBinder(0, null, 0, null, binding, null);
var binder = new ElementBinder(0, null, 0, null, binding);
binder.nestedProtoView = nestedProtoView;
return binder;
}
@@ -45,12 +45,12 @@ export function main() {
}
function createEmptyElBinder() {
return new ElementBinder(0, null, 0, null, null, null);
return new ElementBinder(0, null, 0, null, null);
}
function createComponentElBinder(nestedProtoView = null) {
var binding = createDirectiveBinding(SomeComponent);
var binder = new ElementBinder(0, null, 0, null, binding, null);
var binder = new ElementBinder(0, null, 0, null, binding);
binder.nestedProtoView = nestedProtoView;
return binder;
}
@@ -17,8 +17,6 @@ export function main() {
annotatedDirectives = [
someComponent,
someComponent2,
someViewport,
someViewport2,
someDecorator,
someDecoratorIgnoringChildren,
decoratorWithMultipleAttrs,
@@ -153,27 +151,6 @@ export function main() {
expect(eventBinding.source.source).toEqual('doItGlobal()');
});
//TODO: assertions should be enabled when running tests: https://github.com/angular/angular/issues/1340
describe('viewport directives', () => {
it('should not allow multiple viewport directives on the same element', () => {
expect( () => {
process(
el('<template some-vp some-vp2></template>')
);
}).toThrowError('Only one viewport directive is allowed per element - check '
+ (assertionsEnabled() ? '<template some-vp some-vp2>' : 'null'));
});
it('should not allow viewport directives on non <template> elements', () => {
expect( () => {
process(
el('<div some-vp></div>')
);
}).toThrowError('Viewport directives need to be placed on <template> elements or elements with template attribute - check '
+ (assertionsEnabled() ? '<div some-vp>' : 'null'));
});
});
//TODO: assertions should be enabled when running tests: https://github.com/angular/angular/issues/1340
describe('component directives', () => {
it('should save the component id', () => {
@@ -231,18 +208,6 @@ var someComponent2 = new DirectiveMetadata({
type: DirectiveMetadata.COMPONENT_TYPE
});
var someViewport = new DirectiveMetadata({
selector: '[some-vp]',
id: 'someViewport',
type: DirectiveMetadata.VIEWPORT_TYPE
});
var someViewport2 = new DirectiveMetadata({
selector: '[some-vp2]',
id: 'someViewport2',
type: DirectiveMetadata.VIEWPORT_TYPE
});
var someDecorator = new DirectiveMetadata({
selector: '[some-decor]',
type: DirectiveMetadata.DECORATOR_TYPE
+2 -2
View File
@@ -43,7 +43,7 @@ export function main() {
['properties', MapWrapper.createFromPairs([['propKey', 'propVal']])],
['readAttributes', ['readTest1', 'readTest2']],
['selector', 'testSelector'],
['type', DirectiveMetadata.VIEWPORT_TYPE]
['type', DirectiveMetadata.DECORATOR_TYPE]
]);
var meta = directiveMetadataFromMap(map);
expect(meta.compileChildren).toEqual(false);
@@ -56,7 +56,7 @@ export function main() {
MapWrapper.createFromPairs([['propKey', 'propVal']]));
expect(meta.readAttributes).toEqual(['readTest1', 'readTest2']);
expect(meta.selector).toEqual('testSelector');
expect(meta.type).toEqual(DirectiveMetadata.VIEWPORT_TYPE);
expect(meta.type).toEqual(DirectiveMetadata.DECORATOR_TYPE);
});
});
}
@@ -405,7 +405,7 @@ var multipleContentTagsComponent = new DirectiveMetadata({
var manualViewportDirective = new DirectiveMetadata({
selector: '[manual]',
id: 'manual',
type: DirectiveMetadata.VIEWPORT_TYPE
type: DirectiveMetadata.DECORATOR_TYPE
});
var outerWithIndirectNestedComponent = new DirectiveMetadata({
@@ -441,7 +441,7 @@ var conditionalContentComponent = new DirectiveMetadata({
var autoViewportDirective = new DirectiveMetadata({
selector: '[auto]',
id: '[auto]',
type: DirectiveMetadata.VIEWPORT_TYPE
type: DirectiveMetadata.DECORATOR_TYPE
});
var tabGroupComponent = new DirectiveMetadata({
+1 -1
View File
@@ -16,7 +16,7 @@ import {
import {TestBed} from 'angular2/test';
import {Injector, bind} from 'angular2/di';
import {Component, Viewport} from 'angular2/src/core/annotations_impl/annotations';
import {Component} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view';
import {RootRouter} from 'angular2/src/router/router';
+1 -1
View File
@@ -9,7 +9,7 @@ import {
import {IMPLEMENTS} from 'angular2/src/facade/lang';
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
import {RootRouter, Viewport} from 'angular2/src/router/router';
import {RootRouter} from 'angular2/src/router/router';
import {Pipeline} from 'angular2/src/router/pipeline';
import {RouterOutlet} from 'angular2/src/router/router_outlet';