Home > Mobile >  Having trouble accessing properties of specific JS object instances
Having trouble accessing properties of specific JS object instances

Time:03-05

I'm attempting to make a Google style table visualization that has built-in column filters and have pretty much everything figured out, except how to update properties for the correct table object when a page has more than one instance. I'm aware of the globalThis problem and have gotten around that with a variable that captures the identity of the table object, but it always ends up equaling the id of the last instance created.

I have searched stackoverflow's questions and also looked over some JS training, but still don't find a solution that works for my situation. Or maybe I have, but I didn't understand it well enough. I'm still quite green with JS.

Here's a sample of my code with noted trouble points. It may be a bit much to get the general point across, but I figure it may put my problem into perspective, if that's helpful.

// Declare a unique namespace.
var example = {};

// Attempt to work around globalThis confusion. Ends up pointing only to the last instance of MyTable.
var me = {};

// Class constructor. Parameter container is a DOM element on the client that will contain the chart.
example.MyTable = function(container) {
  this.containerElement = container;
  this.options = {
  filters: [], // Array of objects.
  // etc. ...
  }
  this.view = {rows: null, columns: null}
  // Capture current object to avoid pointing at globalThis. 
  // Problematic with multiple MyTable objects on the page.
  me = this; 
  // 'this.id' works as expected. 'me.id' ends up remaining as the last created MyTable and 
  // messes up other MyTable objects upon additional calls to 'draw()' via events.
  this.id = this.containerElement.id;
}

// Main drawing logic.
// Parameters:
//   'data' is data object to handle.
//   'options' is a name/value map of options that differ from default specified in constructor.
//   'view' holds arrays of specified rows & columns to display or NULL to display all.
example.MyTable.prototype.draw = function(data, options, view) {
  // 'this' works fine for 'options', since the table object has 'this' focus.
  this.setOptions(options) 
  // 'this' works fine for 'view' on page load, but fails for events, 
  // due to the event target having 'this' focus.
  this.setView(view) 
    
  // Code to assemble MyTable and insert into this.containerElement.
  // etc. ...
    
  // Create event listeners to set column filtering and sorting.
  const cols = {};
  for (let col = 0; col < qtyCols; col  ) {
    let colIndex = (this.view.columns ? this.view.columns[col] : col);
    cols[colIndex] = {
      sort: document.querySelector('#col' this.id '-' colIndex ' div.sort'), 
      filter: document.querySelector('#col' this.id '-' colIndex ' div.filter')
    };
    cols[colIndex].sort.addEventListener('click', this.sort); // This is what needs to be fixed.
    cols[colIndex].filter.addEventListener('click', this.showFilterBox); // This too.
  }
};

example.MyTable.prototype.setOptions = function(options){
  // Do stuff to merge user and default options.
  this.options  = options; // Not actual code.
};

example.MyTable.prototype.setView = function(view){
  // Do stuff to merge user and default view.
  this.view  = view; // Not actual code.
};

example.MyTable.prototype.sort = function(e){
  // Using the event target works great for correct UI object reference, but...
  let col = Number(e.target.closest('th').id.substring(e.target.closest('th').id.indexOf('-') 1));
  if(col !== null){
    // ... now I have a problem with addressing the correct table object properties.
    // THIS HERE is my major problem.
    if (me.options.sortColumn === col){me.options.sortAscending = !me.options.sortAscending;}
    else{me.options.sortColumn = col; me.options.sortAscending = true;}
    me.draw();
  }
};

CodePudding user response:

The problem is where you add the event listeners. You don't provide a specific this argument to those callback functions, so they are not called with it. So make sure those handlers are called on the current this object:

cols[colIndex].sort.addEventListener('click', (e) => this.sort(e));
cols[colIndex].filter.addEventListener('click', (e) => this.showFilterBox(e));
  • Related