feat(core): add support for @HostBinding and @HostListener
Example: @Directive({selector: 'my-directive'}) class MyDirective { @HostBinding("attr.my-attr") myAttr: string; @HostListener("click", ["$event.target"]) onClick(target) { this.target = target; } } Closes #3996
This commit is contained in:
@ -1,6 +1,13 @@
|
||||
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';
|
||||
import {
|
||||
DirectiveMetadata,
|
||||
Directive,
|
||||
Property,
|
||||
Event,
|
||||
HostBinding,
|
||||
HostListener
|
||||
} from 'angular2/metadata';
|
||||
|
||||
@Directive({selector: 'someDirective'})
|
||||
class SomeDirective {
|
||||
@ -11,7 +18,7 @@ class SomeChildDirective extends SomeDirective {
|
||||
}
|
||||
|
||||
@Directive({selector: 'someDirective', properties: ['c']})
|
||||
class SomeDirectiveWithProps {
|
||||
class SomeDirectiveWithProperties {
|
||||
@Property() a;
|
||||
@Property("renamed") b;
|
||||
c;
|
||||
@ -40,6 +47,23 @@ class SomeDirectiveWithGetterEvents {
|
||||
}
|
||||
}
|
||||
|
||||
@Directive({selector: 'someDirective', host: {'[c]': 'c'}})
|
||||
class SomeDirectiveWithHostBindings {
|
||||
@HostBinding() a;
|
||||
@HostBinding("renamed") b;
|
||||
c;
|
||||
}
|
||||
|
||||
@Directive({selector: 'someDirective', host: {'(c)': 'onC()'}})
|
||||
class SomeDirectiveWithHostListeners {
|
||||
@HostListener('a')
|
||||
onA() {
|
||||
}
|
||||
@HostListener('b', ['$event.value'])
|
||||
onB(value) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SomeDirectiveWithoutMetadata {}
|
||||
|
||||
@ -52,7 +76,8 @@ export function main() {
|
||||
it('should read out the Directive metadata', () => {
|
||||
var directiveMetadata = resolver.resolve(SomeDirective);
|
||||
expect(directiveMetadata)
|
||||
.toEqual(new DirectiveMetadata({selector: 'someDirective', properties: [], events: []}));
|
||||
.toEqual(new DirectiveMetadata(
|
||||
{selector: 'someDirective', properties: [], events: [], host: {}}));
|
||||
});
|
||||
|
||||
it('should throw if not matching metadata is found', () => {
|
||||
@ -63,39 +88,44 @@ export function main() {
|
||||
it('should not read parent class Directive metadata', function() {
|
||||
var directiveMetadata = resolver.resolve(SomeChildDirective);
|
||||
expect(directiveMetadata)
|
||||
.toEqual(
|
||||
new DirectiveMetadata({selector: 'someChildDirective', properties: [], events: []}));
|
||||
.toEqual(new DirectiveMetadata(
|
||||
{selector: 'someChildDirective', properties: [], events: [], host: {}}));
|
||||
});
|
||||
|
||||
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: []}));
|
||||
var directiveMetadata = resolver.resolve(SomeDirectiveWithProperties);
|
||||
expect(directiveMetadata.properties).toEqual(['c', 'a', 'b: renamed']);
|
||||
});
|
||||
|
||||
it('should work with getters and setters', () => {
|
||||
var directiveMetadata = resolver.resolve(SomeDirectiveWithSetterProps);
|
||||
expect(directiveMetadata)
|
||||
.toEqual(new DirectiveMetadata(
|
||||
{selector: 'someDirective', properties: ['a: renamed'], events: []}));
|
||||
expect(directiveMetadata.properties).toEqual(['a: renamed']);
|
||||
});
|
||||
});
|
||||
|
||||
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']}));
|
||||
expect(directiveMetadata.events).toEqual(['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']}));
|
||||
expect(directiveMetadata.events).toEqual(['a: renamed']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('host', () => {
|
||||
it('should append host bindings', () => {
|
||||
var directiveMetadata = resolver.resolve(SomeDirectiveWithHostBindings);
|
||||
expect(directiveMetadata.host).toEqual({'[c]': 'c', '[a]': 'a', '[renamed]': 'b'});
|
||||
});
|
||||
|
||||
it('should append host listeners', () => {
|
||||
var directiveMetadata = resolver.resolve(SomeDirectiveWithHostListeners);
|
||||
expect(directiveMetadata.host)
|
||||
.toEqual({'(c)': 'onC()', '(a)': 'onA()', '(b)': 'onB($event.value)'});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -73,7 +73,9 @@ import {
|
||||
Query,
|
||||
Pipe,
|
||||
Property,
|
||||
Event
|
||||
Event,
|
||||
HostBinding,
|
||||
HostListener
|
||||
} from 'angular2/metadata';
|
||||
|
||||
import {QueryList} from 'angular2/src/core/compiler/query_list';
|
||||
@ -1625,6 +1627,24 @@ export function main() {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should support host binding decorators',
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
tcb.overrideView(MyComp, new ViewMetadata({
|
||||
template: '<with-prop-decorators></with-prop-decorators>',
|
||||
directives: [DirectiveWithPropDecorators]
|
||||
}))
|
||||
.createAsync(MyComp)
|
||||
.then((rootTC) => {
|
||||
rootTC.detectChanges();
|
||||
var dir = rootTC.componentViewChildren[0].inject(DirectiveWithPropDecorators);
|
||||
dir.myAttr = "aaa";
|
||||
|
||||
rootTC.detectChanges();
|
||||
expect(DOM.getOuterHTML(rootTC.componentViewChildren[0].nativeElement))
|
||||
.toContain('my-attr="aaa"');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
if (DOM.supportsDOMEvents()) {
|
||||
it('should support events decorators',
|
||||
@ -1647,6 +1667,26 @@ export function main() {
|
||||
|
||||
expect(rootTC.componentInstance.ctxProp).toEqual("called");
|
||||
})));
|
||||
|
||||
|
||||
it('should support host listener decorators',
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder,
|
||||
async) => {
|
||||
tcb.overrideView(MyComp, new ViewMetadata({
|
||||
template: '<with-prop-decorators></with-prop-decorators>',
|
||||
directives: [DirectiveWithPropDecorators]
|
||||
}))
|
||||
.createAsync(MyComp)
|
||||
.then((rootTC) => {
|
||||
rootTC.detectChanges();
|
||||
var dir = rootTC.componentViewChildren[0].inject(DirectiveWithPropDecorators);
|
||||
var native = rootTC.componentViewChildren[0].nativeElement;
|
||||
native.click();
|
||||
|
||||
expect(dir.target).toBe(native);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -2203,8 +2243,16 @@ class DirectiveThrowingAnError {
|
||||
|
||||
@Directive({selector: 'with-prop-decorators'})
|
||||
class DirectiveWithPropDecorators {
|
||||
target;
|
||||
|
||||
@Property("elProp") dirProp: string;
|
||||
@Event('elEvent') event = new EventEmitter();
|
||||
|
||||
@HostBinding("attr.my-attr") myAttr: string;
|
||||
@HostListener("click", ["$event.target"])
|
||||
onClick(target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
fireEvent(msg) { ObservableWrapper.callNext(this.event, msg); }
|
||||
}
|
Reference in New Issue
Block a user