Handle undefined variable and error when you pass a variable to a query

Hi, how is the best way to handle and remove undefined error in retool when a query has undefined variable because is passed from JS?

Depends on what you are using?
You can use a CASE statement....

thx im using mongodb, but the problem is not the query but the error for retool the variable is not defined and when i edit the table in console appear all the undefined variable, but when i start the js script all work good. i try to remove this error message.

Please send some screenshots....more information and context will help

Hey there! At the moment, if you're passing a variable using additionalScope there's no way to remove the error in the query editor (note that it also shows up in our docs). It can certainly be confusing though :sweat: and is something the dev team is aware of.

We can report back here when the behavior is changed :slightly_smiling_face:

2 Likes

@Kabirdas I came across this thread while googling about linting errors due to variables to queries via additionalScope.

If the problem is that the query is looking for a variable that is not yet defined/declared (since it will be provided by additionalScope, how about allowing for an area in the query properties to declare such variables?

Queries have sections/tabs at the top, like General, Advanced, etc. What if there was a section called Variables where you could declare and maybe even initialize some to default values?

This would maybe solve the linting issue while also providing a way to document expected or optional variables.

I don't know if this was suggested before, but I think I worked out a way to pass additionalScope variables to queries without causing the linting errors.

In some queries, I already have variables that load from temporary states and which make use of the optional chaining operator.

I figured that instead of passing vars to queries via additionalScope, why not just set those vars to temp states and reference them in the query config?

To keep it neat, I created a new state called queryVars (or whatever name you choose), where I will be setting whatever vars needed inside an object named the same as the query name (for convenience).

retool_query_vars_tempstate2

So I changed my code from this:

addRequestExpense.trigger({
  additionalScope: {
    amount: inputMileageExpense.value,
    type: "expense",
    subtype: "mileage"
  },
  onSuccess: function(data){
    inputMileageExpense.resetValue()
  }
});

To this:

var amount = await queryVars.setIn(["addRequestExpense", "amount"], inputMileageExpense.value);
var amount = await queryVars.setIn(["addRequestExpense", "type"], "expense");
var amount = await queryVars.setIn(["addRequestExpense", "subtype"], "mileage");

addRequestExpense.trigger({
   onSuccess: function(data){
    inputMileageExpense.resetValue()
  }
});

And then in my query, I just reference the temp state, instead of the actual (linting error-inducing) var:

{{queryVars.value?.addRequestExpense?.amount}} <== {{amount}}

I suppose there may be some tradeoffs with this approach, but if the linting errors bother that much, maybe it could be a solution.

I was going to say that for more flexibility, it could be improved slightly by assigning the query name to a variable, in case you need to change the query name in the future and don't want to manually update it in several places.

var queryName = "addRequestExpense";

var amount = await queryVars.setIn([queryName, "amount"], inputMileageExpense.value);
var amount = await queryVars.setIn([queryName, "type"], "expense");
var amount = await queryVars.setIn([queryName, "subtype"], "mileage");

addRequestExpense.trigger({
   onSuccess: function(data){
    inputMileageExpense.resetValue()
  }
});

But then you would still need to update the query name in two places. Wouldn't it be even better to update it only in one place? That's possible also!

var queryName = addRequestExpense;

var amount = await queryVars.setIn([queryName.id, "amount"], inputMileageExpense.value);
var amount = await queryVars.setIn([queryName.id, "type"], "expense");
var amount = await queryVars.setIn([queryName.id, "subtype"], "mileage");

queryName.trigger({
   onSuccess: function(data){
    inputMileageExpense.resetValue()
  }
});

Thus, when you need to use this code for other queries, simply change the query name on the first line and everything flows from there.

:muscle: :beers:

1 Like

This is a really interesting workaround @27shutterclicks, thanks for posting it :star_struck:

And having an area where you can declare which variables designated as additionalScope is a great idea, it's actually something the devs have been playing around with as a way to solve this issue!

1 Like

@kabirdas I took a stab at putting together a mockup of what the variables section discussed before could look like.

Just an idea :slight_smile:.

1 Like

Here is something that worked for me:

query1.trigger({additionalScope: {dynamicParameters: someValue}});

In the query, use this syntax:

{{ typeof dynamicParameters === 'undefined' ? undefined : dynamicParameters}}

And no more linting errors!

2 Likes

Toda @Yaron_Harel, this works great! :muscle::upside_down_face::pray:

1 Like