How to re-render a component, i.e. an ember-light-table

#1

Hi,

I have a use case where I am using ember-light-table, and I want to make the columns configurable by the User. There’s a section of the UI with checkboxes, and the User can check/uncheck what columns they want in the UI, and this is persisted to the API server.

The API portion is working, but when a check/uncheck happens, I want to re-render the ember-light-table with only the columns selected to view. I’ve tried things in the component like:

// maybe this refreshes the route
let route = Ember.getOwner(this).lookup(`route:servicedata`);
route.refresh()

// rerender component
this.rerender()

None of this has worked though.

Is there an Ember hook for this use case or a known pattern to do this?

I also saw this example, but couldn’t get it to work. Should this work?

https://codepen.io/mike-north/pen/vexDK

Thank you in advance.

#2

So with a preface that it’s been a while since I’ve used ember-light-table, and I don’t know what your code looks like… I’ve done something similar and the tricky part is that the table doesn’t observe changes to your column definitions, that is iirc the column definitions you pass into the table at the beginning get copied, so any changes you make to them must be made to the tables columns object, not whatever one you have laying around in the component/controller/wherever. This is probably why rerendering the component isn’t working, because the table is already instantiated with a column definition and you’re not modifying the table’s column object (this is where the preface comes in).

So anyway that’s my guess as to what’s happening, what does your column toggle code look like?

#3

Hi,

Thank you so much for your reply. What you’re saying makes sense. I’m going to look at the ember-light-table column object.

For my column toggle, columns is a computed property with .volatile() added. On click to a list of check boxes for the available columns to view, I change the columns to what the User has selected. This all works, and I can see the list of check boxes updating, it’s just getting the ember-light-table to see the changes that has me stuck.

Great, thanks again. I’m going to try what you said and will report back.

#4

Ah ok yeah that’s kinda what I was guessing. I think what I had to do back in the day was make sure any time my update toggles were updated I reached into the table columns object and toggle the right property on the right column there too. Though it’s possible I set it up to mut the table column object directly… I forget now

#5

I got it working.

My current solution clears all Columns and then adds them back when the User says they want to add/remove a Column. I know that I could do only the one Column, but then I need to calculate if it’s a remove or add and then use the correct ordering when inserting. I might be okay with this. At least it’s working.

Thank you so much for your help. I looked at the “ember-light-table” source code for Table, Column classes, and light-table.js and it helped me understand.

For my solution, I’m using ember-multiselect-checkboxes, it has you define a list of checkboxes like so:

{{multiselect-checkboxes
  options=allColumnNames
  selection=selectedColumns
  onchange=(action 'onChangeSelectedColumns')
}}

The options is a list of strings of available checkboxes, selection is the list of the currently selected.

Then, on a change, this action is called: onChangeSelectedColumns

When that action is called, I have a couple of functions to persist User config to API and to generate the object structure that ember-light-table is expecting, then I call this code, and it updates the Columns, and they get re-rendered.

selectedColumns: computed('columnNames.[]', function() {
  const rawToColumnName = this.get('rawToColumnName');
  const columnNames = this.get('columnNames')
  const selectedColumns = columnNames.map(x => rawToColumnName[x]);
  if (this.table !== undefined) {
    // clear current columns
    this.table.columns.clear()
    // add back only selected columns
    const columns = this.getOrderedColumns(selectedColumns);
    columns.map(x => this.table.columns.pushObject(new Column(x)));
  }
  return selectedColumns;
}),

Thank you again sir! Sigh of relief here. I was very stuck on this :wink:

#6

Awesome! Glad you got a working solution. I had to read a lot of the source to get there too, I typically find that I wait too long to do that because it’s often a great way to find out what’s going on. Anyway, good luck with your code!

1 Like