jquery widget shares data when multiple instance are created

javascript, jquery, jquery-plugins, widget

Solution

The problem was the _checkedIds array was global to the widget instead of in individual context.

Added this line to the _create method:

this._checkedIds = [];

And removed this line from the widget:

_checkedIds: [],

Problem

I created a a jquery widget and all was working, until I needed another instance. That's when I noticed the two instances were sharing the same data. The plugin is supposed to keep track of which rows are checked in a table so I dont' have to calc them everytime I need to use them. If i insantiate widget on two tables, click one row on one table - both tables will have the same data. This happens with both tables. I've only created a couple of jquery widgets so I'm not sure how this happens, but I have stepped through the code and can see it happening. It seems like I'm using the widget factory incorrectly. Thanks for any help in advance! Here is the widget code. ``` $.widget('ui.selectAndFilter', { _init: function () { }, _create: function () { var self = this; self.options.$mainTable = $(self.element).addClass(this.options.cssWidgetClass); self.options.$mainTable.find('tbody tr').bind('click', function (e) { self._onClick(e, $(this), false); //Need to determine what todo with last param - redrawTables }); }, options: { cssWidgetClass: 'select-and-filter', cssSelectedClass: 'selected', $mainTable: {}, childTables: [], canMultiSelect: false, clickFinishedCallbacks: [], minCount: 1 }, destroy: function () { $(this.element).removeClass(this.options.cssWidgetClass); }, _checkedIds: [], checkRow: function ($tr) { if ($.isDigit($tr)) $tr = $(this.options.$mainTable.find('tbody tr:eq(' + $tr + ')')); if ($tr.length) { var id = $tr.addClass(this.options.cssSelectedClass).find(':checkbox').attr('checked', true).val(); this._addId(id); } return this; }, _uncheckRow: function ($tr) { if ($tr.length) { var id = $tr.removeClass(this.options.cssSelectedClass).find(':checkbox').attr('checked', false).val(); return this._removeId(id); } }, uncheckAllRows: function () { var self = this; this.options.$mainTable.find('tr.' + this.options.cssSelectedClass).each(function () { self._uncheckRow($(this)); }); return self; }, _removeId: function (id) { this._checkedIds.splice(this._checkedIds.indexOf(id), 1); return this._checkedIds; }, _addId: function (id) { if (this._checkedIds.indexOf(id) == -1) this._checkedIds.push(id); return this._checkedIds; }, _onClick: function (event, $tr, redrawTables) { if ($tr.hasClass(this.options.cssSelectedClass) && this._checkedIds.length > this.options.minCount) { this._uncheckRow($tr); } else { if (!this.options.canMultiSelect) { this.uncheckAllRows(); } this.checkRow($tr); } this.redrawTables(); this._trigger('click'); }, redrawTables: function () { $.each(this.options.childTables, function () { this.fnDraw(); }); }, checkedIds: function () { return this._checkedIds; } }); ``` And then the code to instantiate them. ``` tables['schedule'].selectAndFilter({canMultiSelect:selectMulti, childTables: redrawTables}); tables['start'].selectAndFilter({canMultiSelect: selectMulti}) tables['batch'].selectAndFilter({minCount:0}); ```

Original source