fix(destroy): Cleanup event listeners on destroy

Event listeners attached to elements inside the root datatable wrapper are automatically removed
when the root element is removed from DOM. But, there are event listeners which are attached to
window and body, those have to be manually removed. This commit introduces an internal event system,
through which we destroy global event handlers.
This commit is contained in:
Faris Ansari 2018-07-10 12:00:41 +05:30
parent f9714673b4
commit bddb3c27ce
4 changed files with 46 additions and 11 deletions

View File

@ -78,9 +78,13 @@ export default class ColumnManager {
}
});
$.on(document.body, 'click', (e) => {
const deactivateDropdownOnBodyClick = (e) => {
if (e.target.matches(toggleClass)) return;
deactivateDropdown();
};
$.on(document.body, 'click', deactivateDropdownOnBodyClick);
this.instance.on('onDestroy', () => {
$.off(document.body, 'click', deactivateDropdownOnBodyClick);
});
const dropdownItems = this.options.headerDropdown;
@ -126,7 +130,7 @@ export default class ColumnManager {
startX = e.pageX;
});
$.on(document.body, 'mouseup', (e) => {
const onMouseup = (e) => {
document.body.classList.remove('dt-resize');
if (!$resizingCell) return;
isDragging = false;
@ -137,9 +141,13 @@ export default class ColumnManager {
this.setColumnWidth(colIndex);
this.style.setBodyStyle();
$resizingCell = null;
};
$.on(document.body, 'mouseup', onMouseup);
this.instance.on('onDestroy', () => {
$.off(document.body, 'mouseup', onMouseup);
});
$.on(document.body, 'mousemove', (e) => {
const onMouseMove = (e) => {
if (!isDragging) return;
const finalWidth = startWidth + (e.pageX - startX);
const {
@ -154,6 +162,10 @@ export default class ColumnManager {
width: finalWidth
});
this.setColumnHeaderWidth(colIndex);
};
$.on(document.body, 'mousemove', onMouseMove);
this.instance.on('onDestroy', () => {
$.off(document.body, 'mousemove', onMouseMove);
});
}

View File

@ -100,6 +100,7 @@ class DataTable {
destroy() {
this.wrapper.innerHTML = '';
this.style.destroy();
this.fireEvent('onDestroy');
}
appendRows(rows) {
@ -193,7 +194,22 @@ class DataTable {
}
fireEvent(eventName, ...args) {
this.events[eventName].apply(this, args);
// fire internalEventHandlers if any
// and then user events
const handlers = [
...(this._internalEventHandlers[eventName] || []),
this.events[eventName]
].filter(Boolean);
for (let handler of handlers) {
handler.apply(this, args);
}
}
on(event, handler) {
this._internalEventHandlers = this._internalEventHandlers || {};
this._internalEventHandlers[event] = this._internalEventHandlers[event] || [];
this._internalEventHandlers[event].push(handler);
}
log() {

View File

@ -32,7 +32,8 @@ export default {
onRemoveColumn(column) {},
onSwitchColumn(column1, column2) {},
onSortColumn(column) {},
onCheckRow(row) {}
onCheckRow(row) {},
onDestroy() {}
},
sortIndicator: {
asc: '↑',

View File

@ -30,18 +30,24 @@ export default class Style {
}
bindResizeWindow() {
this.onWindowResize = this.onWindowResize.bind(this);
this.onWindowResize = throttle(this.onWindowResize, 300);
if (this.options.layout === 'fluid') {
$.on(window, 'resize', throttle(() => {
this.distributeRemainingWidth();
this.refreshColumnWidth();
this.compensateScrollbarWidth();
this.setBodyStyle();
}, 300));
$.on(window, 'resize', this.onWindowResize);
}
}
onWindowResize() {
this.distributeRemainingWidth();
this.refreshColumnWidth();
this.compensateScrollbarWidth();
this.setBodyStyle();
}
destroy() {
this.styleEl.remove();
$.off(window, 'resize', this.onWindowResize);
}
setStyle(selector, styleObject) {