Javascript in Retool

A quick breakdown of important Javascript methods for building in Retool

Javascript Basics

Because Javascript is such an integral part in building in Retool, we’ll be going over specific JS concepts that are particularly important in Retool. If you’re brand new to Javascript/programming in general, there are a few external resources that can help you get started.

There’s a lot of overlap between Javascript Basics and Javascript in Retool, so if you’re already familiar with the basics, feel free to skip this section and jump straight to Javascript in Retool!

You can think of programming at a high level as just: manipulating data with logic. Retool is all about showing and manipulating your data with drag-and-drop buttons, tables, maps, etc.

So first, we’ll cover data in general, how you can represent data, and then how you write logic to show and manipulate that data in Retool.

Data types

Everything in Javascript is an object, which means it’s just a thing with some properties (like a length) and some built-in methods that can manipulate this thing.

🚧

Javascript object vs Javascript Object

In Javascript, essentially all data is referred to as an object. Within this broad category, there is a specific Object data type, which we'll learn about next.

To avoid confusion, I’m going to capitalize Object when we’re referring to the specific data type that looks like this {name: "Sparta", age: 9}, rather than the general term object which broadly refers to data in Javascript.

Javascript has the following common data types, and all are valid in Retool.

Data typeDescriptionExample
StringA value surrounded by quotes. If a number is surrounded by quotes, it’s a string."hi there" , "5" or "true"
NumberA number value. Numbers are also not surrounded by quotes.5
BooleanA true or false value. true and false are reserved keywords that don’t need to be (and shouldn’t be) surrounded in quotes.true
ArrayA list-like, ordered data structure that can store multiple data types surrounded by hard brackets.[5, 'hi', [1, 0]]
ObjectAn un-ordered data structure with key:value pairs surrounded by curly braces and separated by commas.{name: "Sparta", age: 9, good_dog: true}
Data typeDescriptionExample
JSONJavaScript Object Notation is a data format with properties but no dedicated methods. It’s a compact text-based format that is surrounded by curly brackets and contains double quoted strings for keys and values. Single quotes are not valid. Common data type when working with APIs.{ "employees": [{"first_name":"Dwight", "last_name":"Schrute"}, {"first_name":"Pam", "last_name":"Beasley"}]
}

Data Conversion

Managing data types is a fundamental concept that comes up fairly often when manipulating data in Retool. Let’s say you want to get the sum of all the prices in your inventory, but the price column is stored as a string in your database. You can use Javascript data conversion methods to turn those strings into sum-able integers!

MethodDescriptionExample
parseInt("")String → Integer
number.toString()Number (integer, float/decimal, etc.) → String
[“3.5”, “3”].map(Number)Array of strings → Array of integers

Truthy vs Falsy

Because of Javascript’s under-the-hood type casting, all data is either true or false. Numbers can be true or false, words/strings can be true or false. Since true and false are reserved keywords in Javascript that refer directly to the Boolean type true or false, we say “truthy” or “falsy” as the category that data can fall under. Everything is truthy, except for the following 7 falsy values:

  1. the boolean false
  2. the keyword null
  3. the keyword undefined
  4. the numeric data type NaN
  5. the empty string "" or empty array []
  6. the number 0
  7. the BigInt 0n

Q: Is "0" truthy or falsy?
A: Truthy. It’s a non-empty string (truthy).

Q: Is -0 truthy or falsy?
A: Falsy. It evaluates to just 0 (falsy).

Q: Is "false" truthy or falsy?
A: Truthy. It’s a non-empty string (truthy).

More on truthy vs falsy in Javascript here.

Operators

A comparison operator compares its operands (the values before and after the operator) and returns true if the statement is truthy, or false if the statement is falsy.

Comparison OperatorDescriptionExample
>Greater than
<Less than
>=Greater than or equal
<=Less than or equal

Logical operators will also return a boolean depending on the truthiness (or falsiness) of the statement, with the exception of the || and && operators which can return a non-boolean, depending on the operands.

Logical OperatorNameDescriptionExample
OR
&&ANDx && y

Returns x if falsy; otherwise, returns y.

When used with Boolean values,

- returns true if both operands are true
- returns false if one is false.


!NOT!x

Returns a Boolean of the reversed truthiness/falsiness of x






==Equalsx == y

Returns true if the expressions match, false if they don’t.

Data types not considered.


===Strict* equalsx === y

Returns true if the expressions match, false if they don’t.

Data types considered.


!=Does not equalx != y

Returns true if the expressions don’t match, false if they do.

Data types not considered.


!==Strict* inequalsx !== y

Returns true if the expressions don’t match, false if they do.

Data types considered.


*Strict: This includes the data object’s type in the comparison. Strict comparisons are an infamous JS rabbit hole, feel free to watch this video if you’d like to learn more than you'd like to learn!

JSON and Data

There are two main concepts at play here: accessing data in an Object and accessing data in an array.

Then, in the Javascript in Retool section, we can begin thinking about accessing data in an Object in an array in an Object. This is referred to as nested data, which is how Retool queries to your database or API will return data.

Accessing data in an Object

Values in an Object can be accessed using either dot notation (object_name.key_name) or bracket notation (object_name['key_name']). When working with dot notation, property identifies can only be alphanumeric (and _ and $). Dot notation can be limiting (properties can’t start with a number), but adding a . after an object will pull up a helpful autocomplete menu in Retool. More on that below!

Here’s an example where we first define an Object with the name obj1, then access the value held by the 'greeting' key:

const obj1 = { 'greeting': ['hi', 'bye'], 'number': 5, 0: 1 }
return obj1['greeting']  // this returns ['hi', 'bye']

Retool will offer autocomplete options when writing Javascript. If you have an Object (which also includes queries or components, like text1) and aren’t sure which columns, properties or methods you can access, type .

In this case, dot notation is better than bracket notation since a [ will not bring up the autocomplete menu.

`text1.` will bring up a menu of all the methods/functions and properties available to `text1`, along with an example and their type`text1.` will bring up a menu of all the methods/functions and properties available to `text1`, along with an example and their type

text1. will bring up a menu of all the methods/functions and properties available to text1, along with an example and their type

`getUsers.data.` shows a menu of the available columns`getUsers.data.` shows a menu of the available columns

getUsers.data. shows a menu of the available columns

Accessing data in an array

Values in an array can be accessed using the index, or numeric location, of the target. The index always starts at 0, so the first element of an array can be accessed using array[0].

Here’s an example:

const arr1 = ['dog', 'cat', 'frog']
return arr1[1]  // this returns 'cat'

Javascript in Retool

Now we’re at the fun part.

Data in Retool can be manipulated using Javascript. Data objects have properties that can be referenced. For example, you can access a query’s data property via query.data, and a Text Input component’s inputted value via textinput.value and a Table component’s selected row via table.selectedRow.data.

Example of query1.data , which is an Object filled with arrays, where each array matches a column from the database tableExample of query1.data , which is an Object filled with arrays, where each array matches a column from the database table

Imagine you have a database. This database stores user information—id, name, email and so on. Once you write a SQL query to get this data from your database into Retool, how would you display this data?

You guessed it—Javascript! You can use Javascript on the query.data value returned from the query you just ran. We’re going to go over a few commonly used Javascript methods in Retool that would help accomplish this.

{{ }}—Double curlies

In Retool, Javascript can be written between {{ }} or directly in the JS query type, which we’ll get into later. You can also reference the values of Retool components from within {{ }}! More on pulling data from your components here.

This Button Component is using JS in between {{ }} to be disabled when the Checkbox Component isn’t checked.This Button Component is using JS in between {{ }} to be disabled when the Checkbox Component isn’t checked.

Javascript in between {{ }} is limited in a few ways. To output a value from a set of {{ }}, it needs to be a self executing function, method, or single value like {{ query1.data.map(row=>row.id) }} or {{ query1.data.id.length }}. You can’t run any Retool-specific methods from inside them, like text1.setValue(). (Those Retool-specific methods must be run from a JS query, and complicated if-else statements are easier to manage inside of a Transformer, which we'll get into next.)

You can access and use the output from any query. For example, {{ getProducts.data }} returns the following data where getProducts is a SQL query to get data from a products table in a database.

Here’s what getProducts.data looks like:

{
"id":["1", "2", "3"],
"name":["Stucture and Interpretation of Computer Programs","Godel, Escher, Bach","The Seasoned Schemer"],
"quantity":[998001,77777,12563]
}

You can then use {{ getProducts.data }} in a Table Component to display it!

The most common example of {{ }} in action:

The Table Component accepts data as an Object of keys (column names) that point to values (column values).The Table Component accepts data as an Object of keys (column names) that point to values (column values).

Ternaries

Since you can’t write if else logic in between {{ }} , but you want to conditionally return data, you can use ternaries. Ternaries are a one-line version of an if else statement (MDN docs here).

condition ? execute if condition is true : execute if condition is false

Since everything in Javascript is either truthy or falsy, the condition section can be a statement with a comparison operator (e.g. === or >=), or just a plain old object (e.g. table1.data or checkbox1.value). If table1.data exists (has data, and is not empty), the condition will evaluate as true and the first action will execute. See example below!

The ternary in a text component’s value checks if table1.data exists, then prints the corresponding text.The ternary in a text component’s value checks if table1.data exists, then prints the corresponding text.

JS Queries

JS queries are a special query type in Retool that allow you to write multi-line Javascript, trigger other queries, download data from your app, set temporary state to store data in your current browser session, etc. Go ahead and read our JS query docs on all the cool things they can do!

One thing you can’t do is set table data manually in a JS query. You can return some data, then use the JS query’s data in the table’s value field, but table1.data = something won’t work, nor will something like table1.hidden = true. Components in Retool are generally read only, and are only modifiable with specific methods, found in the Scripting Retool docs linked above (and here).

Quick note: for security reasons, all JS runs in a sandbox.

If JS ran directly on your page, other people in your org could inject malicious scripts to end users, including yourself. To prevent that, we execute all JS in a separate iframe, on a different domain.

That means that inside of your preloaded JS, you won't be able to use jQuery, or other hosted libraries to create your own components, listen to events on the Retool page, etc. You can, however, import libraries! Here is a section of our docs that walk through it. You would need to add it to the libraries section in settings > advanced, then you should be able to get access to the library’s methods.

JS Queries vs JS Transformers

JS queries are best for calling JS methods (ie query.trigger(), state1.setValue(), etc) while JS transformers are best for returning a single value or data object.

JS QueriesJS Transformers
Format of Retool data (other queries, components, etc) to be used in the querytextinput1.value{{ textinput1.value }}
Runs……when manually triggered…on input change + page load
Executable Retool-specific methods- query.trigger()
- state1.setValue()
- table.selectRow(index)
- modal.open()
- utils.downloadFile(data, fileName, fileType)
- More methods here!
🚫
Return valueDoesn’t need a return value, can just be used to run methods listed aboveMust have a return value
How can I access the returned value?{{ query.data }}{{ transformer.value }}

Viewing your data

We’re going to take a quick detour and take a look at the ways you can view your data before we get into accessing nested, and more complicated data structures. Viewing your data gives you a birds-eye view of the maze that is nested data, and therefore, makes it easier to access the values you’re looking for.

To recap from the beginning, once you successfully query your database, you’ll get data back and into your Retool app. This data can be accessed in the data property of the query, like
{{ getPeople.data }}. {{ getPeople.data }} is a nested Object (an Object with Objects with arrays inside).

Retool offers 3 main ways to view this query data: the Query Preview, the Left Panel and the (green) Value Preview.

Query PreviewLeft PanelValue Preview
FormatTableExpandable/interactiveRaw
Data types indicated?🚫
LocationBelow the query after clicking “Preview”Left PanelBelow a value input after clicking in said input
Example
  1. Query Preview

The Preview option will show your data formatted as a table, with easy to view headers/column names and values.

  1. Left Panel (also named the Model Browser)

The Left Panel has information about all of your query, component, transformer, temporary state, global variables (ie current_user or urlparams) data in Retool. You can expand out the object you’re interested in to learn more about its data structure.

Each object (in bold) will have its type next to it (in gray) like {} or [], as well as its length in number of items or number of keys.

Each key represents different properties of a query, like error to indicate the presence of an error or isFetching to let you know if the query is still running. It also has the data key, the most important key for queries.


  1. Value preview

This preview shows the raw data. You can even copy the value to your clipboard.

Again, all 3 screenshots are showing getUsers.data, just presented in different ways. Now let’s learn how to actually access, and use, this data!

Accessing nested data

This is one of the most important concepts in Retool. We’ll learn how to access specific data returned from your database (via queries) so you can start using that data in your apps.

In the example below, the getPeople query has the data key/property (the syntax is interchangeable here), which has the keys first, id and last, which are the column names from our people table. The first key points to an array of first name strings.

{{ getPeople.data }} returns the following data. Again, it’s the same as the data we see above in the Left Panel screenshot, just presented differently.

{
"id":[1,2,3,4,5,6,7,8,9,10],
"first":["Myrtle","Nellie","Theodore","Randall","Ralph","Travis","Randy","Christopher","Eula","Jane"],
"last":["Barber","Bowman","Phelps","Hale","Wise","Daniel","Harrison","Allen","Austin","Lewis"]
}

Let’s say we want to access the array of ids to use in a dropdown to allow end users to select the user they’d like more info on. To access the array of ids, we can use {{ getPeople.data.id }}.


Data Conversion

There are two data conversion methods that are special to Retool:
formatDataAsArray and formatDataAsObject.

Data from SQL queries are returned as an Object of arrays, where each key is a column name that points to an array of column values.

If you want to show the data as an array of Objects instead (where each Object represents a row), you can use the helper function formatDataAsArray like so: {{formatDataAsArray(sqlQuery.data)}}

MethodDescriptionRetool use case
formatDataAsArrayObject of arrays → Array of Objects

In the context of Retool, it will convert an Object of table column arrays to an array of row Objects.
getActors.data:




{{ formatDataAsArray(getActors.data``) }}:

formatDataAsObjectArray of Objects → Object of arrays

In the context of Retool, it will convert an array of row Objects to an Object of table column arrays.
Reverse of above

Array methods

Similarly, whether you need to find the row of data based on the id selected from a Dropdown component, or add new values to the array stored in Retool’s temp state (docs here), you’ll need to use Javascript!

MethodDescriptionExampleRetool use case
.lengthReturns the length of an arraygetItems.data.length returns the total number of items returned from the query
.joinCombines elements from an array into a string, with an optional separator (commonly a space)

.join ‘s reverse function is .split , MDN docs here and here


.indexOfReturns the position of the first occurrence of the given value
.includesReturns true or false if an array includes the value passed into the methodgetItems.data.id.includes("1") returns true if an item with id of 1 exists in the items returned from the query
.forEachLoop through each element in an array
.filterReturns a new array with the elements from the original array that match a specified condition
.mapReturns a new array with the results of running a specified function on each element of the original array

getItems.data.id.map(Number) returns an array of the ids (originally strings) turned into numbers
.pushAdd an item to the end of an array[7, 8, 9].push(10) // 4

Note: [7, 8, 9].push(10) will return the new length of the array, but it will still make the change “in the background”

.concatMerge 2 or more arrays


Let’s add some values to our state!

const newValues = ['cat', 'kitten']
state1.setValue(state1.value.concat(newValues))

Now our state looks like this:

.reduceReduces the array to a single value by running a provided function for each value of the array (from left-to-right)


Where getOrders.data.charge_total is an array of numbers
Useful to sum all values in an array, and can be done in between {{ }} without needing to use a JS query or transformer

Dates

When dealing with dates in Retool, you’ll most likely want to use moment(). You can use it anywhere you can use Javascript, like so: {{ moment() }}. Moment is an awesome, external JavaScript library that helps you manage dates in the browser that comes pre-installed in Retool, and has its own docs here.

Most SQL databases store dates in a date or datetime type column, so if you have a string date (like ’12/25/1995’), your database will likely reject it. You’ll need to convert the string into a proper date type before sending it to your database; this is where Moment comes in.

Let’s go over a few of the most relevant Moment methods!

MethodDescriptionExample
moment()Returns the current datetime in the users current timezone
moment('date string', 'new format')Converts a date string in the given format to a date object
.format('new format')Formats your current date. See docs for full table on acceptable date format options (e.g. dddd, Do, etc.)moment().format(); // "2014-09-08T08:02:17-05:00"
moment().format("MMMM Do YYYY, h:mm:ss a"); // "February 14th 2010, 3:25:50 pm"
moment().format("ddd, hA"); // "Sun, 3PM"
moment().format("[Today is] dddd"); // "Today is Sunday"
moment('gibberish').format('YYYY MM DD'); // "Invalid date"


.unix()Outputs a Unix timestamp
.isBefore('second date')Returns a boolean if first given date is before the second given date
.isAfter('second date')Returns a boolean if first given date is after the second given date
.add``(duration, 'duration type')Adds a given duration and duration typemoment()—today




moment().add(7, '``days``'``)—today + 7 days

.subtract(duration, 'duration type')Subtracts a given duration and duration type (I.E. ‘days’, ‘hours)moment()—today




moment().subtract(7, 'days')—today - 7 days

.diff(moment, string)Returns the difference between two moments, as the specified string duration (I.E. ‘days’, ’hours’)
.tz('timezone')Changes the timezone
.utc()moment("date", "current format").utc()
returns the given date in UTC.

moment.utc("date", "current format")
will not convert to UTC. It’s only setting your input to UTC time. It’s basically a way of indicating that the time you input is in UTC.


Retool’s preview is in UTC





What’s Next

You made it out! Take a break (you deserve it), and then return to Reschool's homepage to learn more about your next mission.

Did this page help you?