Skip to content

Commit

Permalink
fix: unsubscribe everything event & nullify DOM elements avoid detach…
Browse files Browse the repository at this point in the history
… elements (#551)

* fix: nullify every DOM elements to avoid detach elements
- see this Stack Overflow [question](https://stackoverflow.com/questions/16901759/javascript-memory-leaks-detached-dom-tree) for reference

* refactor: nullify element in correct scope

* refactor: nullify every elements to avoid detached elements

* refactor: on destroy we should call selector destroy if exist

* refactor: remove event handler when destroying controls

* refactor: add flag to destroy all elements

* refactor: make sure all event listeners are unsubscribed

* refactor: fix code indentation
  • Loading branch information
ghiscoding committed Nov 14, 2020
1 parent 1b549b1 commit e3f4961
Show file tree
Hide file tree
Showing 14 changed files with 187 additions and 21 deletions.
15 changes: 13 additions & 2 deletions controls/slick.columnpicker.js
Expand Up @@ -79,9 +79,18 @@
function destroy() {
_grid.onHeaderContextMenu.unsubscribe(handleHeaderContextMenu);
_grid.onColumnsReordered.unsubscribe(updateColumnOrder);
if ($list) {
$list.remove();
}
if ($menu) {
$menu.off("click").remove();
}
$(document.body).off("mousedown", handleBodyMouseDown);
$("div.slick-columnpicker").hide(_options && _options.columnPicker && _options.columnPicker.fadeSpeed);
$menu.remove();
$(".slick-columnpicker." + _gridUid).hide(_options && _options.columnPicker && _options.columnPicker.fadeSpeed);
$columnTitleElm = null;
$list = null;
$menu = null;
$(window).off("beforeunload");
}

function handleBodyMouseDown(e) {
Expand Down Expand Up @@ -151,6 +160,8 @@
.fadeIn(_options && _options.columnPicker && _options.columnPicker.fadeSpeed);

$list.appendTo($menu);
$li = null;
$input = null;
}

function updateColumnOrder() {
Expand Down
30 changes: 24 additions & 6 deletions controls/slick.gridmenu.js
Expand Up @@ -189,17 +189,15 @@
// if header row is enabled, we need to resize it's width also
var enableResizeHeaderRow = (_options.gridMenu && _options.gridMenu.resizeOnShowHeaderRow != undefined) ? _options.gridMenu.resizeOnShowHeaderRow : _defaults.resizeOnShowHeaderRow;
if (enableResizeHeaderRow && _options.showHeaderRow) {
var $headerrow = $('.' + _gridUid + '.slick-headerrow');
$headerrow.attr('style', 'width: calc(100% - ' + gridMenuWidth + 'px)');
$('.' + _gridUid + '.slick-headerrow').attr('style', 'width: calc(100% - ' + gridMenuWidth + 'px)');
}

$button = $('<button class="slick-gridmenu-button"/>');
if (_options.gridMenu && _options.gridMenu.iconCssClass) {
$button.addClass(_options.gridMenu.iconCssClass);
} else {
var iconImage = (_options.gridMenu && _options.gridMenu.iconImage) ? _options.gridMenu.iconImage : "../images/drag-handle.png";
var $btnImage = $('<img src="' + iconImage + '"/>');
$btnImage.appendTo($button);
$('<img src="' + iconImage + '"/>').appendTo($button);
}
$button.insertBefore($header);

Expand Down Expand Up @@ -232,18 +230,34 @@
_grid.onColumnsReordered.unsubscribe(updateColumnOrder);
_grid.onBeforeDestroy.unsubscribe();
_grid.onSetOptions.unsubscribe();
$("div.slick-gridmenu." + _gridUid).remove();
deleteMenu();
$(window).off("beforeunload");
}

/** Delete the menu DOM element but without unsubscribing any events */
function deleteMenu() {
$(document.body).off("mousedown." + _gridUid, handleBodyMouseDown);
$("div.slick-gridmenu." + _gridUid).hide();
$menu.remove();
$button.remove();
if ($button) {
$button.remove();
}
if ($menu) {
$menu.remove();
}
if ($customMenu) {
$customMenu.remove();
}
if ($header) {
$header.attr('style', 'width: 100%'); // put back original width
}
$customTitleElm = null;
$columnTitleElm = null;
$customMenu = null;
$header = null;
$list = null;
$button = null;
$menu = null;
}

function populateCustomMenus(options, $customMenu) {
Expand Down Expand Up @@ -326,6 +340,9 @@
if (item.textCssClass) {
$text.addClass(item.textCssClass);
}
$icon = null;
$li = null;
$text = null;
}
}

Expand Down Expand Up @@ -469,6 +486,7 @@
return;
}
}
$input = null;
}

function handleBodyMouseDown(e) {
Expand Down
12 changes: 7 additions & 5 deletions plugins/slick.autotooltips.js
Expand Up @@ -22,7 +22,7 @@
maxToolTipLength: null,
replaceExisting: true
};

/**
* Initialize plugin.
*/
Expand All @@ -32,15 +32,15 @@
if (options.enableForCells) _grid.onMouseEnter.subscribe(handleMouseEnter);
if (options.enableForHeaderCells) _grid.onHeaderMouseEnter.subscribe(handleHeaderMouseEnter);
}

/**
* Destroy plugin.
*/
function destroy() {
if (options.enableForCells) _grid.onMouseEnter.unsubscribe(handleMouseEnter);
if (options.enableForHeaderCells) _grid.onHeaderMouseEnter.unsubscribe(handleHeaderMouseEnter);
}

/**
* Handle mouse entering grid cell to add/remove tooltip.
* @param {jQuery.Event} e - The event
Expand All @@ -61,9 +61,10 @@
}
$node.attr("title", text);
}
$node = null;
}
}

/**
* Handle mouse entering header cell to add/remove tooltip.
* @param {jQuery.Event} e - The event
Expand All @@ -75,8 +76,9 @@
if (column && !column.toolTip) {
$node.attr("title", ($node.innerWidth() < $node[0].scrollWidth) ? column.name : "");
}
$node = null;
}

// Public API
$.extend(this, {
"init": init,
Expand Down
3 changes: 3 additions & 0 deletions plugins/slick.cellmenu.js
Expand Up @@ -177,6 +177,9 @@
if ($menu && $menu.remove) {
$menu.remove();
}
$commandTitleElm = null;
$optionTitleElm = null;
$menu = null;
}

function createMenu(e) {
Expand Down
7 changes: 6 additions & 1 deletion plugins/slick.cellrangedecorator.js
Expand Up @@ -59,6 +59,10 @@
return _elem;
}

function destroy() {
hide();
}

function hide() {
if (_elem) {
_elem.remove();
Expand All @@ -69,7 +73,8 @@
$.extend(this, {
"pluginName": "CellRangeDecorator",
"show": show,
"hide": hide
"hide": hide,
"destroy": destroy
});
}
})(jQuery);
9 changes: 7 additions & 2 deletions plugins/slick.cellrangeselector.js
Expand Up @@ -48,6 +48,11 @@

function destroy() {
_handler.unsubscribeAll();
_$activeCanvas = null;
_canvas = null;
if (_decorator && _decorator.destroy) {
_decorator.destroy();
}
}

function getCellDecorator() {
Expand Down Expand Up @@ -126,7 +131,7 @@
e.pageY - _$activeCanvas.offset().top + _rowOffset
);

// ... frozen column(s),
// ... frozen column(s),
if ( _gridOptions.frozenColumn >= 0 && (!_isRightCanvas && (end.cell > _gridOptions.frozenColumn)) || (_isRightCanvas && (end.cell <= _gridOptions.frozenColumn)) ) {
return;
}
Expand Down Expand Up @@ -164,7 +169,7 @@
)
});
}

function getCurrentRange() {
return _currentlySelectedRange;
}
Expand Down
4 changes: 4 additions & 0 deletions plugins/slick.cellselectionmodel.js
Expand Up @@ -45,6 +45,10 @@
_selector.onCellRangeSelected.unsubscribe(handleCellRangeSelected);
_selector.onBeforeCellRangeSelected.unsubscribe(handleBeforeCellRangeSelected);
_grid.unregisterPlugin(_selector);
_canvas = null;
if (_selector && _selector.destroy) {
_selector.destroy();
}
}

function removeInvalidRanges(ranges) {
Expand Down
2 changes: 1 addition & 1 deletion plugins/slick.checkboxselectcolumn.js
Expand Up @@ -266,7 +266,7 @@
}

function addCheckboxToFilterHeaderRow(grid) {
grid.onHeaderRowCellRendered.subscribe(function (e, args) {
_handler.subscribe(grid.onHeaderRowCellRendered, function (e, args) {
if (args.column.field === "sel") {
$(args.node).empty();
$("<span id='filter-checkbox-selectall-container'><input id='header-filter-selector" + _selectAll_UID + "' type='checkbox'><label for='header-filter-selector" + _selectAll_UID + "'></label></span>")
Expand Down
3 changes: 3 additions & 0 deletions plugins/slick.contextmenu.js
Expand Up @@ -194,6 +194,9 @@
if ($menu && $menu.remove) {
$menu.remove();
}
$commandTitleElm = null;
$optionTitleElm = null;
$menu = null;
}

function createMenu(e) {
Expand Down
4 changes: 3 additions & 1 deletion plugins/slick.draggablegrouping.js
Expand Up @@ -56,6 +56,7 @@
var _defaults = {
};
var onGroupChanged = new Slick.Event();
var _handler = new Slick.EventHandler();

/**
* Initialize plugin.
Expand All @@ -76,7 +77,7 @@
setupColumnDropbox();


_grid.onHeaderCellRendered.subscribe(function (e, args) {
_handler.subscribe(_grid.onHeaderCellRendered, function (e, args) {
var column = args.column;
var node = args.node;
if (!$.isEmptyObject(column.grouping)) {
Expand Down Expand Up @@ -143,6 +144,7 @@
*/
function destroy() {
onGroupChanged.unsubscribe();
_handler.unsubscribeAll();
}


Expand Down
11 changes: 11 additions & 0 deletions plugins/slick.headermenu.js
Expand Up @@ -132,6 +132,12 @@
function destroy() {
_handler.unsubscribeAll();
$(document.body).off("mousedown", handleBodyMouseDown);
if ($menu) {
$menu.remove();
}
$menu = null;
$activeHeaderColumn = null;
$menu = null;
}


Expand Down Expand Up @@ -181,6 +187,7 @@
$el
.on("click", showMenu)
.appendTo(args.node);
$el = null;
}
}

Expand Down Expand Up @@ -283,6 +290,9 @@
if (item.textCssClass) {
$text.addClass(item.textCssClass);
}
$icon = null;
$text = null;
$li = null;
}

var leftPos = $(this).offset().left;
Expand Down Expand Up @@ -313,6 +323,7 @@
// Stop propagation so that it doesn't register as a header click event.
e.preventDefault();
e.stopPropagation();
$menuButton = null;
}


Expand Down
6 changes: 5 additions & 1 deletion slick.compositeeditor.js
Expand Up @@ -111,6 +111,7 @@
}

options.destroy && options.destroy();
editors = [];
};


Expand Down Expand Up @@ -200,10 +201,13 @@
$labelElm.removeClass("invalid");
}
}
$validationElm = null;
$labelElm = null;
$editorElm = null;
}
idx++;
}

$targetElm = null;

if (errors.length) {
return {
Expand Down
24 changes: 24 additions & 0 deletions slick.dataview.js
Expand Up @@ -49,6 +49,7 @@
var compiledFilter;
var compiledFilterWithCaching;
var filterCache = [];
var _grid = null;

// grouping
var groupingInfoDefaults = {
Expand Down Expand Up @@ -99,6 +100,27 @@
suspend = false;
refresh();
}

function destroy() {
items = [];
idxById = null;
rowsById = null;
filter = null;
updated = null;
sortComparer = null;
filterCache = [];
filteredItems = [];
compiledFilter = null;
compiledFilterWithCaching = null;

if (_grid && _grid.onSelectedRowsChanged && _grid.onCellCssStylesChanged) {
_grid.onSelectedRowsChanged.unsubscribe();
_grid.onCellCssStylesChanged.unsubscribe();
}
if (self.onRowsOrCountChanged) {
self.onRowsOrCountChanged.unsubscribe();
}
}

function setRefreshHints(hints) {
refreshHints = hints;
Expand Down Expand Up @@ -1074,6 +1096,7 @@
*/
function syncGridSelection(grid, preserveHidden, preserveHiddenOnSelectionChange) {
var self = this;
_grid = grid;
var inHandler;
selectedRowIds = self.mapRowsToIds(grid.getSelectedRows());
var onSelectedRowIdsChanged = new Slick.Event();
Expand Down Expand Up @@ -1187,6 +1210,7 @@
// methods
"beginUpdate": beginUpdate,
"endUpdate": endUpdate,
"destroy": destroy,
"setPagingOptions": setPagingOptions,
"getPagingInfo": getPagingInfo,
"getIdPropertyName": getIdPropertyName,
Expand Down

0 comments on commit e3f4961

Please sign in to comment.