feat(core): add support for @Property and @Event decorators
Example: @Directive({selector: 'my-selector'}) class MyDirective { @Property() prop; @Property('el-prop') prop2; @Event() event; @Event('el-event') event2; } Closes #3992
This commit is contained in:
@ -1,36 +0,0 @@
|
||||
import {ddescribe, describe, it, iit, expect, beforeEach} from 'angular2/test_lib';
|
||||
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
|
||||
import {DirectiveMetadata, Directive} from 'angular2/metadata';
|
||||
|
||||
@Directive({selector: 'someDirective'})
|
||||
class SomeDirective {
|
||||
}
|
||||
|
||||
@Directive({selector: 'someChildDirective'})
|
||||
class SomeChildDirective extends SomeDirective {
|
||||
}
|
||||
|
||||
class SomeDirectiveWithoutAnnotation {}
|
||||
|
||||
export function main() {
|
||||
describe("DirectiveResolver", () => {
|
||||
var reader;
|
||||
|
||||
beforeEach(() => { reader = new DirectiveResolver(); });
|
||||
|
||||
it('should read out the Directive annotation', () => {
|
||||
var directiveMetadata = reader.resolve(SomeDirective);
|
||||
expect(directiveMetadata).toEqual(new Directive({selector: 'someDirective'}));
|
||||
});
|
||||
|
||||
it('should throw if not matching annotation is found', () => {
|
||||
expect(() => { reader.resolve(SomeDirectiveWithoutAnnotation); })
|
||||
.toThrowError('No Directive annotation found on SomeDirectiveWithoutAnnotation');
|
||||
});
|
||||
|
||||
it('should not read parent class Directive annotations', function() {
|
||||
var directiveMetadata = reader.resolve(SomeChildDirective);
|
||||
expect(directiveMetadata).toEqual(new Directive({selector: 'someChildDirective'}));
|
||||
});
|
||||
});
|
||||
}
|
102
modules/angular2/test/core/compiler/directive_resolver_spec.ts
Normal file
102
modules/angular2/test/core/compiler/directive_resolver_spec.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import {ddescribe, describe, it, iit, expect, beforeEach} from 'angular2/test_lib';
|
||||
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
|
||||
import {DirectiveMetadata, Directive, Property, Event} from 'angular2/metadata';
|
||||
|
||||
@Directive({selector: 'someDirective'})
|
||||
class SomeDirective {
|
||||
}
|
||||
|
||||
@Directive({selector: 'someChildDirective'})
|
||||
class SomeChildDirective extends SomeDirective {
|
||||
}
|
||||
|
||||
@Directive({selector: 'someDirective', properties: ['c']})
|
||||
class SomeDirectiveWithProps {
|
||||
@Property() a;
|
||||
@Property("renamed") b;
|
||||
c;
|
||||
}
|
||||
|
||||
@Directive({selector: 'someDirective', events: ['c']})
|
||||
class SomeDirectiveWithEvents {
|
||||
@Event() a;
|
||||
@Event("renamed") b;
|
||||
c;
|
||||
}
|
||||
|
||||
|
||||
@Directive({selector: 'someDirective'})
|
||||
class SomeDirectiveWithSetterProps {
|
||||
@Property("renamed")
|
||||
set a(value) {
|
||||
}
|
||||
}
|
||||
|
||||
@Directive({selector: 'someDirective'})
|
||||
class SomeDirectiveWithGetterEvents {
|
||||
@Event("renamed")
|
||||
get a() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SomeDirectiveWithoutMetadata {}
|
||||
|
||||
export function main() {
|
||||
describe("DirectiveResolver", () => {
|
||||
var resolver;
|
||||
|
||||
beforeEach(() => { resolver = new DirectiveResolver(); });
|
||||
|
||||
it('should read out the Directive metadata', () => {
|
||||
var directiveMetadata = resolver.resolve(SomeDirective);
|
||||
expect(directiveMetadata)
|
||||
.toEqual(new DirectiveMetadata({selector: 'someDirective', properties: [], events: []}));
|
||||
});
|
||||
|
||||
it('should throw if not matching metadata is found', () => {
|
||||
expect(() => { resolver.resolve(SomeDirectiveWithoutMetadata); })
|
||||
.toThrowError('No Directive annotation found on SomeDirectiveWithoutMetadata');
|
||||
});
|
||||
|
||||
it('should not read parent class Directive metadata', function() {
|
||||
var directiveMetadata = resolver.resolve(SomeChildDirective);
|
||||
expect(directiveMetadata)
|
||||
.toEqual(
|
||||
new DirectiveMetadata({selector: 'someChildDirective', properties: [], events: []}));
|
||||
});
|
||||
|
||||
describe('properties', () => {
|
||||
it('should append directive properties', () => {
|
||||
var directiveMetadata = resolver.resolve(SomeDirectiveWithProps);
|
||||
expect(directiveMetadata)
|
||||
.toEqual(new DirectiveMetadata(
|
||||
{selector: 'someDirective', properties: ['c', 'a', 'b: renamed'], events: []}));
|
||||
});
|
||||
|
||||
it('should work with getters and setters', () => {
|
||||
var directiveMetadata = resolver.resolve(SomeDirectiveWithSetterProps);
|
||||
expect(directiveMetadata)
|
||||
.toEqual(new DirectiveMetadata(
|
||||
{selector: 'someDirective', properties: ['a: renamed'], events: []}));
|
||||
});
|
||||
});
|
||||
|
||||
describe('events', () => {
|
||||
it('should append directive events', () => {
|
||||
var directiveMetadata = resolver.resolve(SomeDirectiveWithEvents);
|
||||
expect(directiveMetadata)
|
||||
.toEqual(new DirectiveMetadata(
|
||||
{selector: 'someDirective', properties: [], events: ['c', 'a', 'b: renamed']}));
|
||||
});
|
||||
|
||||
it('should work with getters and setters', () => {
|
||||
var directiveMetadata = resolver.resolve(SomeDirectiveWithGetterEvents);
|
||||
expect(directiveMetadata)
|
||||
.toEqual(new DirectiveMetadata(
|
||||
{selector: 'someDirective', properties: [], events: ['a: renamed']}));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
@ -64,7 +64,17 @@ import {
|
||||
ChangeDetectorGenConfig
|
||||
} from 'angular2/src/core/change_detection/change_detection';
|
||||
|
||||
import {Directive, Component, View, ViewMetadata, Attribute, Query, Pipe} from 'angular2/metadata';
|
||||
import {
|
||||
Directive,
|
||||
Component,
|
||||
View,
|
||||
ViewMetadata,
|
||||
Attribute,
|
||||
Query,
|
||||
Pipe,
|
||||
Property,
|
||||
Event
|
||||
} from 'angular2/metadata';
|
||||
|
||||
import {QueryList} from 'angular2/src/core/compiler/query_list';
|
||||
|
||||
@ -1597,6 +1607,48 @@ export function main() {
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
describe('property decorators', () => {
|
||||
it('should support property decorators',
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
tcb.overrideView(
|
||||
MyComp, new ViewMetadata({
|
||||
template: '<with-prop-decorators el-prop="aaa"></with-prop-decorators>',
|
||||
directives: [DirectiveWithPropDecorators]
|
||||
}))
|
||||
.createAsync(MyComp)
|
||||
.then((rootTC) => {
|
||||
rootTC.detectChanges();
|
||||
var dir = rootTC.componentViewChildren[0].inject(DirectiveWithPropDecorators);
|
||||
expect(dir.dirProp).toEqual("aaa");
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
|
||||
if (DOM.supportsDOMEvents()) {
|
||||
it('should support events decorators',
|
||||
inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
|
||||
tcb = tcb.overrideView(
|
||||
MyComp, new ViewMetadata({
|
||||
template: `<with-prop-decorators (el-event)="ctxProp='called'">`,
|
||||
directives: [DirectiveWithPropDecorators]
|
||||
}));
|
||||
|
||||
var rootTC;
|
||||
tcb.createAsync(MyComp).then(root => { rootTC = root; });
|
||||
tick();
|
||||
|
||||
var emitter =
|
||||
rootTC.componentViewChildren[0].inject(DirectiveWithPropDecorators);
|
||||
emitter.fireEvent('fired !');
|
||||
|
||||
tick();
|
||||
|
||||
expect(rootTC.componentInstance.ctxProp).toEqual("called");
|
||||
})));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -2148,3 +2200,11 @@ class OtherDuplicateDir {
|
||||
class DirectiveThrowingAnError {
|
||||
constructor() { throw new BaseException("BOOM"); }
|
||||
}
|
||||
|
||||
@Directive({selector: 'with-prop-decorators'})
|
||||
class DirectiveWithPropDecorators {
|
||||
@Property("elProp") dirProp: string;
|
||||
@Event('elEvent') event = new EventEmitter();
|
||||
|
||||
fireEvent(msg) { ObservableWrapper.callNext(this.event, msg); }
|
||||
}
|
Reference in New Issue
Block a user