Skip to content

Commit

Permalink
feat(base): Add emit() method for dispatching custom events
Browse files Browse the repository at this point in the history
* Refactor custom event logic out of mdl-icon-toggle

This is needed by mdl-menu as well in order for it to emit events and
therefore work with the select element.

Part of #4475
[#126819221]
  • Loading branch information
traviskaufman committed Nov 9, 2016
1 parent 849fca9 commit 78958b0
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 17 deletions.
1 change: 1 addition & 0 deletions packages/mdl-base/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ export class MyComponent extends MDLComponent {
| `getDefaultFoundation()` | Returns an instance of a foundation class properly configured for the component. Called when no foundation instance is given within the constructor. Subclasses **must** implement this method. |
| `initialSyncWithDOM()` | Called within the constructor. Subclasses may override this method if they wish to perform initial synchronization of state with the host DOM element. For example, a slider may want to check if its host element contains a pre-set value, and adjust its internal state accordingly. Note that the same caveats apply to this method as to foundation class lifecycle methods. Defaults to a no-op. |
| `destroy()` | Subclasses may override this method if they wish to perform any additional cleanup work when a component is destroyed. For example, a component may want to deregister a window resize listener. |
| `emit(type: string, data: Object)` | Dispatches a custom event of type `type` with detail `data` from the component's root node. This is the preferred way of dispatching events within our vanilla components. |

#### Static Methods

Expand Down
14 changes: 14 additions & 0 deletions packages/mdl-base/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,18 @@ export default class MDLComponent {
// attached. An example of this might be deregistering a resize event from the window object.
this.foundation_.destroy();
}

// Fires a cross-browser-compatible custom event from the component root of the given type,
// with the given data.
emit(evtType, evtData) {
let evt;
if (typeof CustomEvent === 'function') {
evt = new CustomEvent(evtType, {detail: evtData});
} else {
evt = document.createEvent('CustomEvent');
evt.initCustomEvent(evtType, false, false, evtData);
}

this.root_.dispatchEvent(evt);
}
}
18 changes: 1 addition & 17 deletions packages/mdl-icon-toggle/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class MDLIconToggle extends MDLComponent {
getAttr: (name, value) => this.root_.getAttribute(name, value),
setAttr: (name, value) => this.root_.setAttribute(name, value),
rmAttr: (name, value) => this.root_.removeAttribute(name, value),
notifyChange: evtData => this.emitChange_(evtData)
notifyChange: evtData => this.emit('MDLIconToggle:change', evtData)
});
}

Expand Down Expand Up @@ -106,20 +106,4 @@ export class MDLIconToggle extends MDLComponent {
refreshToggleData() {
this.foundation_.refreshToggleData();
}

// NOTE(traviskaufman): This will most likely be refactored into a generic event mechanism
// within mdl-base at some point. Until the time when it's needed by more than just this component, we'll
// keep it simple and local for now.
emitChange_(evtData) {
const evtType = 'MDLIconToggle:change';
let evt;
if (typeof CustomEvent === 'function') {
evt = new CustomEvent(evtType, {detail: evtData});
} else {
evt = document.createEvent('CustomEvent');
evt.initCustomEvent(evtType, false, false, evtData);
}

this.root_.dispatchEvent(evt);
}
}
19 changes: 19 additions & 0 deletions test/unit/mdl-base/component.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,22 @@ test("provides a default destroy() method which calls the foundation's destroy()
t.doesNotThrow(() => td.verify(foundation.destroy()));
t.end();
});

test('#emit dispatches a custom event with the supplied data', t => {
const root = document.createElement('div');
const f = new FakeComponent(root);
const handler = td.func('eventHandler');
let evt = null;
td.when(handler(td.matchers.isA(Object))).thenDo(evt_ => {
evt = evt_;
});
const data = {evtData: true};
const type = 'customeventtype';

root.addEventListener(type, handler);
f.emit(type, data);
t.true(evt !== null);
t.equal(evt.type, type);
t.deepEqual(evt.detail, data);
t.end();
});

0 comments on commit 78958b0

Please sign in to comment.