Async JS Query and isFetching not working

When you run an async js query like this for example:

//jsInsertTemplate
  (async () => {
    //debugger
    currentTemplate.setValue(txtAddTemplateName.value)
    await qryTemplateInsert.trigger()
    let d = await qryTemplatesSelect.trigger()
    let d2 = await qryTemplatesSelectNewest.trigger()
    //debugger
    await qryAddSection.trigger({additionalScope: {template_id:d2.template_id[0]}})
    const idx = tblTemplates.data.template_id.indexOf(d2.template_id[0])
    if (idx >= 0 ) {
      tblTemplates.selectRow(idx)
    }
	})();

jsInsertTemplate.isFetching is only true for a very short time even while all of those async triggers are still working. So how do I tell if the query is still working without setting some flags in temp vars?

I thought maybe the Keep variable references inside option might help as it does something with async but that option is missing.

Hey Bradley :wave: Unfortunately, I'm not aware of a simpler way to keep track of whether or not all of these queries are fetching within the JS query itself. I think using a separate temp state variable, that you set to true at the onset of this script and to false when all queries have resolved, would be my recommendation here. But please let us know if you've come up with a better solution!

1 Like

That is what I ended up doing and it does work. A pattern I am well familiar with on a few different platforms over the decades!

Hey Bradley, I apologize that I missed this earlier but this is actually a bug on our end :slightly_frowning_face: You can use await top-level in JS Queries which will cause the JS query to run as long as all triggered queries run. This SHOULD allow you to use the JSquery.isFetching value, but that value is currently broken in Retool. It will show correctly in the model browser, but if you use it in any components it always evaluates to false.

We've got a report for this bug in place. While I'm unable to provide a timeline for a fix at the moment, we'll be sure to let you know of any updates! For now, the pattern you already have in place is the best workaround. Sorry again for the misleading initial response. I wanted to circle back and make sure to provide a better explanation :smile:

Is there something special I have to do to make a JS Query allow top-level await? Here's what I see when I try it:

And when I try to run it:

Thank you!

(edit: forgot to mention, I'm running Retool 2.79.13 on-prem)

@aivajoe,

You need to use a self invoking function with an async decorator like so:

(async () => {
  let data = await jsSetView.trigger({additionalScope: {skipSelect: true}})	
  if (data) {
     const myField = data.theField[0]
     return myField
   } else {
     throw new Error("Query returned no data!")
   }	
 })();

Thank you, @bradlymathews. Won't this cause the query to return immediately though? I have an outer query where I trigger two inner queries, and I want the outer query to block until both inner queries are done (for setting a form's "show loading indicator" and "block user input" properties while the queries are in progress).

Also in @everett_smith 's screenshot above, he's using "await" at the top level of his query, without wrapping it in a self-invoking function.

You know, I didn't catch that he was doing it that way. I didn't think you could do that.

@everett_smith, can you fill us in?

Can offer some clarification here! Top-level await is currently available on cloud but for self-hosted users it's a feature flag that's turned off by default.

I also want to toss in a +1 for tracking the status of a query with a temp state.

1 Like

Hey! Just want to give an update here. As for 2.97.1 (Cloud) and 2.97.2 (On-Prem), the isFetching property on JavaScript queries should be functioning properly. If you'd like to use it you can try either using top-level await or having your query return a promise e.g. with the IIFE pattern Bradley was referring to, something like:

return (async () => {
/*
your async function here
*/
})();
1 Like