State value changes being ignored inside JS scripts

When executing code with JavaScript, state values are read only once. Therefore, if a toggle's value changes outside of the script, and you're using a loop or recursive function calls within JavaScript, the updated value is overlooked. This means implementing an abort logic based on state changes is challenging because new state values are ignored during execution.

Example of code.

function recursiveCall(count = 1) {
  // This state is being ignored, i changed the value using a button, this if will never run.
  if (abort.value == true) { 
       console.log('Aborting at:', count);
      return;
  }
  console.log('Recursive call number:', count);

  // Adjusted to access "abort.value"
  if (abort.value || count >= 10) {
    console.log('Stopping recursive calls.');
    return;
  }

  recursiveCall(count + 1);
}

// Initial call
recursiveCall();

Please fix this if is a bug or give me a solution!

I'm not totally understanding where the state is getting set here but it sounds like you want to select Keep variable references inside the query in sync with your app from the Advanced tab in the query. This will keep state in sync but comes with a performance penalty.

Also, if(abort.value == true) and if(abort.value) are functionally the same statement. The only difference is that the second block will be accessed if count >= 10. Is this intentional?

As @kschirrmacher mentioned above, the Keep variable references inside the query in sync with your app will likely solve your issue.

Linking to a discussion last year where it came up that some of these headaches could be prevented by having this state in sync by default, with the option to turn it off for performance optimization.

My vote is that such an inversion is preferable for the general user.

1 Like

My use case is a bulk processing, it's a script that get a list and process in a rest API, i'm just trying to implement an abort button. My button set the state abort to true, but te JS script keeps with old value while the list is being processed.

Is your script running asynchronously? If not, is it possible that it runs 10 times immediately and although those queries are still running when you select abort, it's already too late for the script to read the value?

ya i was thinking async causes that problem also.

.setValue() returns a promise. so if you don't await it any code below that line will not use the new value as the promise won't be fulfilled until the function/code block returns. Before anything that uses JS returns/ends Retool ensures every promise is fulfilled. that also means you don't need to do await Promise.all(myPromiseArray) because this also returns a promise, which retool will handle for us... unless you need to do a .then/.catch

setValue is async? No way! Let me test this.

Yeah, but even setting the state using a button, my loops still only see the old value. Don't know how to fix it easily.

Can you console log from inside of your recursive and from the button and share the output? I'm still stuck on my theory that you're queueing up 10 queries immediately because you're not awaiting the response from each one.

Example:

Screenshot 2024-02-14 at 11.53.02 AM

If you await the query in each loop, the code doesn't run until the previous query finishes and the next loop can read the updated value.

const recursiveCall = async (count = 1) =>  {
  console.log('recursive')
  console.log('Recursive call number:', count);

  if (count >= 10) {
    console.log('Stopping recursive calls.');
    return;
  }
  
  await query2.trigger()
  recursiveCall(count + 1);
}

recursiveCall();

theres a little checkbox at the bottom of the advanced tab, says something like 'keep variables in sync ' or something similar... put a check to it then try again. ill send a pic when im not on my phone if itll help

Thanks @bobthebear