Skip to content

Commit a96b817

Browse files
committed
fix($event): Fix the $event local within the '(event)' expression to properly match Angular 2.
The $event local should now properly reflect either: - The DOM event object for normal events such as (click), (keyup), etc - The Output payload for @Output-based events fixes #88 BREAKING CHANGE: Before: Previously the `$event.detail` property was needed to access the @output's payload. After: Now you access the payload directly with just `$event`.
1 parent 8dfa6cd commit a96b817

File tree

7 files changed

+55
-24
lines changed

7 files changed

+55
-24
lines changed

API.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ Every input can be bound in three different ways, just like Angular 2:
251251

252252
###### Output Usage
253253

254-
Every output can be listened for using the `(event)="handler()"` syntax.
254+
Every output can be listened for using the `(event)="handler()"` syntax. The `$event` var can be used your expression like this, `(event)="handler($event)"`, and will either be a reference to your output's payload for custom outputs, or a reference to the DOM event object for standard DOM events.
255255

256256
**Important:** We do **not** support the optional `on-event` syntax.
257257

@@ -272,6 +272,11 @@ class MenuDropdown {
272272
}
273273
```
274274

275+
Then you'd use it like so:
276+
```html
277+
<menu-dropdown (option-select)="ctrl.optionSelected($event)"></menu-dropdown>
278+
```
279+
275280
## Component Life Cycle Hooks
276281

277282
Life cycle hooks are methods added to a Component or Directive. If the hook is present then it will be fired at the designated time. Read about each hook and when and why you would use it.

lib/decorators/component.spec.ts

+6-7
Original file line numberDiff line numberDiff line change
@@ -768,12 +768,11 @@ describe('@Component', function(){
768768
directives: [Child],
769769
template: `
770770
<h1 class="greeting">{{ctrl.foo}} World!</h1>
771-
<child [foo]="ctrl.foo" (foo-changed)="ctrl.fooChanged($event)"></child>
771+
<child [foo]="ctrl.foo" (foo-changed)="ctrl.foo=$event"></child>
772772
`
773773
})
774774
class Parent {
775775
foo = "Hello";
776-
fooChanged($event) { this.foo = $event.detail; }
777776
}
778777

779778
let fixture = quickFixture({
@@ -943,13 +942,13 @@ describe('@Component', function(){
943942
fixture.debugElement.componentInstance.bar.should.be.true;
944943
});
945944

946-
it('passes along event detail via dom event', () => {
945+
it('sets $event to dom event', () => {
947946
@Component({ selector: 'foo', template: 'x', outputs: ['output'] })
948947
class Foo { }
949948

950949
let fixture = quickFixture({
951950
directives: [Foo],
952-
template: `<foo ng-init="ctrl.bar=false" (output)="ctrl.bar=$event.detail"></foo>`
951+
template: `<foo ng-init="ctrl.bar=false" (output)="ctrl.bar=$event"></foo>`
953952
});
954953

955954
fixture.debugElement.componentInstance.bar.should.be.false;
@@ -959,7 +958,7 @@ describe('@Component', function(){
959958
fixture.debugElement.componentViewChildren[0].nativeElement.dispatchEvent(new CustomEvent('output', {detail}));
960959
this.clock.tick();
961960

962-
fixture.debugElement.componentInstance.bar.should.eql('hello');
961+
fixture.debugElement.componentInstance.bar.detail.should.eql('hello');
963962
});
964963

965964
it('creates a directive triggered by event emitter', () => {
@@ -1000,15 +999,15 @@ describe('@Component', function(){
1000999
fixture.debugElement.componentInstance.bar.should.be.true;
10011000
});
10021001

1003-
it('passes along event detail via event emitter', () => {
1002+
it('sets $event to payload from event emitter', () => {
10041003
@Component({ selector: 'foo', template: 'x', outputs: ['output'] })
10051004
class Foo {
10061005
output = new EventEmitter();
10071006
}
10081007

10091008
let fixture = quickFixture({
10101009
directives: [Foo],
1011-
template: `<foo ng-init="ctrl.bar=false" (output)="ctrl.bar=$event.detail"></foo>`
1010+
template: `<foo ng-init="ctrl.bar=false" (output)="ctrl.bar=$event"></foo>`
10121011
});
10131012

10141013
fixture.debugElement.componentInstance.bar.should.be.false;

lib/decorators/input-output.spec.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -404,12 +404,11 @@ describe('@Input Decorator', function(){
404404
directives: [Child],
405405
template: `
406406
<h1 class="greeting">{{ctrl.foo}} World!</h1>
407-
<child [foo]="ctrl.foo" (foo-changed)="ctrl.fooChanged($event)"></child>
407+
<child [foo]="ctrl.foo" (foo-changed)="ctrl.foo=$event"></child>
408408
`
409409
})
410410
class Parent {
411411
foo = "Hello";
412-
fooChanged($event) { this.foo = $event.detail; }
413412
}
414413

415414
fixture = quickFixture({
@@ -608,7 +607,7 @@ describe('@Output Decorator', function(){
608607

609608
let fixture = quickFixture({
610609
directives: [Foo],
611-
template: `<foo ng-init="ctrl.bar=false" (output)="ctrl.bar=$event.detail"></foo>`
610+
template: `<foo ng-init="ctrl.bar=false" (output)="ctrl.bar=$event"></foo>`
612611
});
613612

614613
fixture.debugElement.componentInstance.bar.should.be.false;
@@ -618,7 +617,7 @@ describe('@Output Decorator', function(){
618617
fixture.debugElement.componentViewChildren[0].nativeElement.dispatchEvent(new CustomEvent('output', {detail}));
619618
this.clock.tick();
620619

621-
fixture.debugElement.componentInstance.bar.should.eql('hello');
620+
fixture.debugElement.componentInstance.bar.detail.should.eql('hello');
622621
});
623622

624623
it('creates a directive triggered by event emitter', () => {
@@ -667,7 +666,7 @@ describe('@Output Decorator', function(){
667666

668667
let fixture = quickFixture({
669668
directives: [Foo],
670-
template: `<foo ng-init="ctrl.bar=false" (output)="ctrl.bar=$event.detail"></foo>`
669+
template: `<foo ng-init="ctrl.bar=false" (output)="ctrl.bar=$event"></foo>`
671670
});
672671

673672
fixture.debugElement.componentInstance.bar.should.be.false;

lib/events/events.spec.ts

+30-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,36 @@ describe('Auto-generated Event Directives', function(){
3434
asserts.should.eql(allEvents.length);
3535
});
3636

37-
xit('bubbles the events', () => {
37+
it('sets $event local to DOM event', () => {
38+
let fixture = quickFixture({
39+
template: `
40+
<div ng-init="ctrl.evt=false">
41+
<button (click)="ctrl.evt=$event">Click Me</button>
42+
</div>
43+
`
44+
});
45+
46+
fixture.debugElement.componentInstance.evt.should.be.false;
47+
fixture.debugElement.find('button').nativeElement.click();
48+
fixture.debugElement.componentInstance.evt.should.be.instanceOf(MouseEvent);
49+
});
50+
51+
it('sets $event local hidden detail._output property if present', () => {
52+
let fixture = quickFixture({
53+
template: `
54+
<div ng-init="ctrl.evt=false">
55+
<button (click)="ctrl.evt=$event">Click Me</button>
56+
</div>
57+
`
58+
});
59+
60+
fixture.debugElement.componentInstance.evt.should.be.false;
61+
let event = new CustomEvent('click', { detail: { _output: 'foo' }});
62+
fixture.debugElement.find('button').nativeElement.dispatchEvent(event);
63+
fixture.debugElement.componentInstance.evt.should.eql('foo');
64+
});
65+
66+
it.skip('bubbles the events', () => {
3867
let fixture = quickFixture({
3968
template: `
4069
<div ng-init="ctrl.clicked=false" (click)="ctrl.clicked=true">

lib/events/events.ts

+7-9
Original file line numberDiff line numberDiff line change
@@ -48,24 +48,22 @@ function resolve(): any[]{
4848
public expression: any;
4949

5050
constructor($parse: ng.IParseService, public $element: JQuery, $attrs: ng.IAttributes, public $scope: ng.IScope){
51-
5251
let { name: attrName } = parseSelector(selector);
5352
this.expression = $parse($attrs[attrName]);
5453
$element.on(event, e => this.eventHandler(e));
5554
$scope.$on('$destroy', () => this.onDestroy());
5655
}
5756

5857
eventHandler($event: any = {}){
59-
let detail = $event.detail;
60-
61-
if(!detail && $event.originalEvent && $event.originalEvent.detail){
62-
detail = $event.originalEvent.detail;
58+
if ($event.detail && $event.detail._output !== undefined) {
59+
$event = $event.detail._output;
6360
}
64-
else if(!detail){
65-
detail = {};
61+
62+
if($event.originalEvent && $event.originalEvent.detail && $event.originalEvent.detail._output) {
63+
$event = $event.detail._output;
6664
}
67-
68-
this.expression(this.$scope, Object.assign(detail, { $event }));
65+
66+
this.expression(this.$scope, {$event});
6967
this.$scope.$applyAsync();
7068
}
7169

lib/properties/outputs-builder.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export default function(instance: any, element: INgForwardJQuery, $scope: ng.ISc
2020
// dispatch a bubbling event onto the element
2121
const create = (eventKey: string, emitter: EventEmitter) => {
2222
return emitter.subscribe((data: any) => {
23-
let event = new CustomEvent(eventKey, { detail: data, bubbles: false });
23+
let event = new CustomEvent(eventKey, { detail: {_output: data}, bubbles: false });
2424
element[0].dispatchEvent(event);
2525
});
2626
};

lib/tests/utils.ts

+1
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ export function quickFixture({
1616

1717
let builder = new tcb.TestComponentBuilder();
1818

19+
//noinspection TypeScriptUnresolvedFunction
1920
return builder.create(Test);
2021
};

0 commit comments

Comments
 (0)