Write and run JavaScript
Learn how to run JavaScript in your Retool apps.
You can write JavaScript to interact with components and queries, which is useful for adding custom logic to your apps. This guide covers common use cases of JavaScript in Retool. For more comprehensive references, visit the JavaScript API reference and the Component reference.
To get started, open the code list and create a query. Select Query in the JavaScript section.
In the editor, you can write code to set component properties, trigger queries, and access useful JavaScript libraries.
To ensure safety and security for all users, certain interactions with the browser and context outside of Retool apps can't be run. For example, you can't access browser events or use libraries like jQuery.
Run an API request for each row in a table
This examples makes an API request for each row in a table, and then shows any errors returned in the process.
1. Add a table
Add a Table component to your app. Select Use an array in the Data source dropdown menu, then paste this JSON into the Data source attribute.
[
{
"id": 1,
"name": "Hanson Deck",
"email": "hanson@deck.com",
"sales": 37
},
{
"id": 2,
"name": "Sue Shei",
"email": "sueshei@example.com",
"sales": 550
},
{
"id": 3,
"name": "Jason Response",
"email": "jason@response.com",
"sales": 55
},
{
"id": 4,
"name": "Cher Actor",
"email": "cher@example.com",
"sales": 424
},
{
"id": 5,
"name": "Erica Widget",
"email": "erica@widget.org",
"sales": 243
}
]
2. Create a query
Create a query using the RestQuery (restapi) resource. Set the Action type to Post and use this URL: https://approvals.tryretool.com/api/users/approve?email={{table1.data[i].email}}. The URL parameters are populated automatically.
By default, the i property is 0 but JavaScript in a subsequent step will increment this value so the query runs on each row.

3. Add a Button and Text components
Add a Button and two Text components to your app. Status shows the query's progress and Errors displays any errors while the query runs.
4. Write the JavaScript query
Create a JavaScript query named query2 and add the following JavaScript.
var rows = table1.data;
var errors = "";
var total = rows.length;
function runQuery(i) {
// Update the Status text
Status.setValue("Progress: " + (i.toString() + "/" + total.toString()));
if (i >= rows.length) {
console.log("Finished running all queries");
return;
}
console.log("Running query for row", i);
query1.trigger({
additionalScope: { i: i }, // This is where we override the `i` variable
// You can use the argument to get the data with the onSuccess function
onSuccess: function (data) {
runQuery(i + 1);
},
onFailure: function (error) {
// Update the Errors text
errors += "Found error at line " + i.toString() + ": " + error + "\n\n";
Errors.setValue(errors);
runQuery(i + 1);
},
});
}
runQuery(0);
5. Add an event handler to your button
After saving query2, add an event handler to your button that triggers the JavaScript query.

Now click the Submit button to test the app. As the query runs on each row, the status updates and errors are displayed. Since the API endpoint at https://approvals.tryretool.com/api/users/approve doesn't exist, all the requests fail.

Clear state after running a query
You can use the following snippet to clear state after a query runs.
userInput.setValue("");
emailInput.setValue("");
pricingTierDropdown.setValue(null);
Trigger a query
This snippet programmatically triggers a query.
query1.trigger();
You can also pass additional arguments to customize the behavior of a query.
query1.trigger({
additionalScope: {
name: "hi",
},
// You can use the argument to get the data with the onSuccess function
onSuccess: function (data) {
console.log("Successully ran!");
},
});
The additionalScope option allows you to pass more variables to the query that aren't defined on the global scope. In this example, name is now passed to query1, and query1 can access {{name}}. The onSuccess or onFailure callback is called after the function completes.
Queries that reference values within additionalScope initially show an error because there's no global property of the specified name. This error resolves when you populate the Additional Scope field or save and run the query.
Here's an example of additionalScope used in an app.
Retrieve triggering components
The variable triggeredById returns the name of the component that triggered a query. You can reference this inside of {{ }} in any query to return the name of the component that triggered it. If the query is triggered by another query, triggeredById returns undefined.
text1.setValue("I was triggered by component: " + triggeredById);