Bug - button /variable not reading custom component output

i have come across a strange issue.

I have a custom component which has a value output auditQuestions.ready_to_submit as Boolean true or false

on screen the output is correctly showing the current value:

BUT button shows error as if the component is not defined.
image

when i adjust disabled expression to: {{ auditQuestions.ready_to_submit === false}}

i then tried to load the value in a variable and use the variable. but this is stranger still:

the value of varible in preview shows correctly. BUT the actual value of the varible is ""????

its as if it can read the value. but at the same time cant....

any ideas? or just a bug that needs looking at?

1 Like

Hello @Loni ,

Thanks for sharing your concern — I completely understand the issue you're facing.

In Retool, variables initialized using expressions that reference other components (like auditQuestions.ready_to_submit) can sometimes behave unexpectedly. This typically happens because those variables are evaluated before the referenced components (like queries or temporary states) are fully loaded or bound. As a result, the variable might end up with an incorrect or empty value.

Recommended Solutions

Option 1: Use a Transformer (Recommended)

Instead of relying on a variable, create a Transformer (click the "+" button → select Transformer) with the following logic:

return auditQuestions.ready_to_submit === false;

Then, in the Disabled property of your button, use:

{{ transformer1.value }}

This approach ensures the expression is evaluated after all components have loaded properly, giving you more reliable results.

Option 2: Use the Expression Directly

If your use case is simple, you can directly reference the expression in your button's disabled field like this:

{{ auditQuestions.ready_to_submit === false }}

This eliminates the need for variables or transformers entirely and works well in most cases where the dependent component loads quickly or predictably.

Why This Happens

Retool evaluates variables at the time of initialization. If a referenced component (like a query result or state value) hasn't finished loading yet, the variable may not capture the intended value. Transformers and inline expressions solve this by evaluating after the component state is stable.

Let me know if you'd like help implementing either option — happy to walk you through it!

thanks,

the transformer method seems to work initially BUT if the value updates another strange occurrence.

When the transformer updates its values the button doesnt seem to register this at all.


here the value in auditQuestions.ready_to_submit has updated to true. the transformer has picked this up and when previewing the value it shows as true.
but within the button its still showing the original false value :frowning:

so the button is loading the transformer value once initially and then not reading any changes after it seems. which is strange.

Direct expression within the button throws error saying auditQuestions is not defined.

I would suggest adding an event to your custom component to emit when ready_to_submit changes:

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const auditQuestions: FC = ({ children }: any) => {
  const [ready_to_submit, set_ready_to_submit] = useState(false);

  const onReadyToSubmit = Retool.useEventCallback({
    name: 'onReadyToSubmit', 
  })

  const onNotReadyToSubmit = Retool.useEventCallback({
    name: 'onNotReadyToSubmit ', 
  })

  const onError = Retool.useEventCallback({
    name: 'onError',
  })

  function setReadyStatus(status: boolean){
      try{
          set_ready_to_submit(status);
          if(status){
              onReadyToSubmit();
          }
          else{
              onNotReadyToSubmit();
          }
      }
      catch(Exception e){
          console.log("Unknown Error: ", e);
          onError();
      }
   }
}

now you can add an event in Retool and select 'onReadyToSubmit' then use this to update your variable.

Thank Bob.

I did incorporate an event to try bypass this issue but sadly still there.

created event to trigger anytime the value within the component toggles between true / false.

But sadly same issue. wont update the variable. button wont read the variable, transformer or the value directly from auditQuestions.ready_to_submit

ive tried storing the info into local storage.... wont store. tried 50 - 100 ms via debounce on the event trigger incase values wern't ready yet.... no luck

the issue seems to be on component level as when actually saving data to database from the custom component. this works fine

try using {{ !readyToSubmit.value }} isntead of {{ self.ready_to_submit }}. I'm kinda wondering if the output is actually a string not a boolean. Here's an example of where I've ran into this before:


As you can see, the IDE shows me a JSON object (even the string one in 1st picture says 'string' but shows an object [no surrounding quotes]), but when it comes to using it I discover it actually is being stored as a string.

if this is happening to you, it would def cause problems in any comparison used

Thanks again but sadly no luck.

i feel like ive hit every dead end. tried reading auditQuestions.ready_to_submit:

directly - says auditQuestions is undefined in any button or other component
image

via varible or transformer: variable doesnt work at all. transformer reads the value and shows in perview BUT button or any other component doesn't get the value from the transformer.... not on update anyway.

ive tried via event trigger to set variable, using direct value. usin transformer value... same problem

ive tried setting value to local storage. saves as "" even though review shows correct value....

kinda ran out of things to try from my knowledge... happy to try more if anyone has any ideas or if retool can confirm this is a bug in how custom components have their output values read?

ok found a workaround solution....

i created a query which returns the value of auditQuestions.ready_to_submit

i trigger this to run on the event trigger. the buttons etc.. all seem to be able to read the query correctly.

1 Like

I'm glad to hear you found a workaround, @Loni, but suspect that there might be a scoping issue or something similar at play. :thinking: Whenever one of my custom components isn't working as expected, I'll often just remove and re-add it to the canvas.

There doesn't seem to be an underlying systemic issue, at least, as I was able to implement something similar without any issues.

If you want another pair of eyes, I'd be happy to take a look at your app JSON and custom component code!