Table not selecting row

I have a table (tableMembers) and a form with a save button.
When the button is clicked, it should take some data and insert it into the Retool database, then select the newly inserted row.

Here's the script for the button click:

insertPeople.trigger({onSuccess:(data)=> {
  let id = data.id["0"];

  getPeople.trigger({onSuccess:()=>{
    tableMembers.selectRow({mode:'key',indexType:'data',key:id});
  }});
}})

Unfortunately, this doesn't work. While my 'id' column is a number column, I've tried passing the id in as a number and a string. Neither works. The only thing that works is when I pass in a hard-coded number.

3 Likes

Hey @jdavis,

I think you need to refer to insertPeople.data.result[0].id

The data passed into onSuccess is the return value.

The variable id has the correct value. If I add console.log, it shows the right value.

3 Likes

Ah, sorry I misread your post.

Is the table you're targeting hidden, nested or not visible? There is a known bug about the selectRow method not working if that's the case

No, I saw that bug earlier. However, my table is fully visible.

I think it's a race condition with rendering. Let's say that I have 4 items in the table (with ID's 1-4), and then I insert another item to the table, which would have an auto-incremented seq generated ID of 5.

If I hardcoded the ID between 1 and 4 : tableMembers.selectRow({mode:'key',indexType:'data',key:4});
Then, the row would be selected just fine.

However, if I hardcoded the ID of 5 (knowing that the new item would have a generated ID of 5): tableMembers.selectRow({mode:'key',indexType:'data',key:5});
Then, the row would not be selected.

Again, I'm wondering if the table hasn't been fully rendered and part of the DOM and therefore the item isn't available for selection.

3 Likes

So, I tried something, and it does indeed appear to be a race condition. Here's my updated code, and it works as expected. I'm not sure if this is considered "Solved" or if this is best practice, but at least it works:

insertPeople.trigger({onSuccess:(data)=> {
  let id = data.id["0"];

  getPeople.trigger({onSuccess:()=>{
    setTimeout(()=> {
      tableMembers.selectRow({mode:'key',indexType:'data',key:id});
    }, 1000);
  }});
}})

It would be great if someone from Retool could verify that this is allowed. I know with many web app frameworks, using setTimeout can be problematic.

4 Likes

Hey @jdavis,

Good catch. Coincidentally I had a similar issue a couple of days ago, I have a js query preparing data for an API post call and I added a simple script to my button,

prepareData.Trigger({onSuccess: createInvoice.trigger()})

I kept getting errors on my createInvoice trigger until I manually added the event handler within the query's on success out of the box section, which makes it work seamleslly. It does seem like a bug/race condition when manually writing the onSuccess function.

@Paulo, have tagged this as bug although not sure it is one.

Instead of using setTimeout, it would be ideal if the table component (along with others) had an onrender event.

Currently, the setTimeout assumes that the table will be fully rendered in under a second. However, if this isn't the case, the code won't select a row successfully. I think we should be able to tie into the complete lifecycle of each component.

Something like this, perhaps:

insertPeople.trigger({onSuccess:(data)=> {
  let id = data.id["0"];

  tableMembers.onrender(()=>{
    tableMembers.selectRow({mode:'key',indexType:'data',key:id});
  });

  getPeople.trigger();
}});

(NOTE: I recognize that this code as-is would create a memory leak as it could potentially add multiple instances of the lambda to the onrender event. However, it's just a concept.)

1 Like

Hi @jdavis,

I am thinking this could be solved with the following steps :crossed_fingers:

  1. Set the default value of the selected row to be conditionally equal to insertPeople.data?.id[0], if it exists, otherwise some other default value. Similar to this:
  2. Trigger insertPeople
  3. Trigger getPeople on success

Let me know if this wouldn't work for your use case!

@Tess, Unfortunately, that won't work in my situation. The SQL query returns results as sorted by "[lastname], [firstname]" (the table columns are not sortable, everything is sorted at the query). So, there's no way to know where the new item will be placed in the array.

Hi @jdavis I'm not sure I am following - would you mind sharing screenshots or more details? Is the table paginated?

Since the insert query is returning the newly created id, you can use that as the default primary key to be selected. You'd need to have the primary key value set on the table.