Mobile app tutorial: Write custom logic
Learn how to extend your app's functionality with JavaScript queries and transformers.
As you've learned, anything between curly brackets {{ }}
is processed as JavaScript in Retool. This is great for smaller pieces of code, but sometimes apps require more complex logic. This is where transformers and writing custom JavaScript code come in.
Transformers allow you to write reusable pieces of code. They're often used to manipulate data, and you can access the transformer throughout your app using {{ transformer.value }}
. Transformers execute their code automatically, and aren't explicitly triggered with event handlers or components.
You can write more complex logic using JavaScript. This allows you to trigger queries and configure components, which gives you more control over how your app works. If you create an app with small pieces of code spread throughout it, you might want to write JavaScript queries to centralize that logic instead.
1. Add search functionality
On the peopleListScreen, it'd be useful to search for users instead of scrolling through them. JavaScript transformers update automatically when the object they reference changes, which means you can write a transformer to read the value in a Text Input component and then filter users based on the text.
First, add a Text Input component to the top of the peopleListScreen. By default, the component is added to the bottom of the screen but you can drag and drop components in the left panel to reorder them. Update the Label to Search users.
Open the code list to create a JavaScript transformer. Name it searchUsers
and paste the following code into the editor.
const users = {{ getUsers.data }};
const result = users.filter(user => user.name.toLowerCase().includes({{textInput4.value}}.toLowerCase()));
return result;
This code iterates through each user returned in the getUsers
query, and checks to see if the value in the textInput4
component is contained in the name. The values are converted to lowercase with toLowerCase()
so that search terms don't have to match case exactly.
Make sure to save the transformer, then select the collectionView1
component on the peopleListScreen. Update the Data source to searchUsers
and the Body to {{ item.blocked ? 'Blocked' : 'Allowed' }}
. You can test the search functionality by selecting the Text Input component and typing.
2. Add functionality to block and unblock all users
In a previous step, you added an action to the peopleListScreen for blocking and allowing all users. It's now time to connect that action to some custom JavaScript to perform these bulk actions. The JavaScript queries you'll write identify which users to block or allow and then trigger the appropriate query.
Create a JavaScript query
Open the code list and create a JavaScript query. Name it blockAll
and then paste this code into the editor. Make sure to save the query.
var users = getUsers.data;
const unblockedUsers = users
.map((user, index) => [user, index])
.filter(([user]) => !user.blocked);
let blockIndex = 0;
const blockNext = () => {
// Notify and quit when finished
if (blockIndex >= unblockedUsers.length) {
utils.showNotification({
title: "Success",
description: "Successfully blocked " + unblockedUsers.length + " users.",
notificationType: "success",
duration: 3,
});
// Update table after queries finish
getUsers.trigger();
return;
}
// Get next unblocked user and unblock them
const [unblockedUser, index] = unblockedUsers[blockIndex];
blockAllUsers.trigger({
additionalScope: { i: index },
onSuccess: function () {
blockIndex++;
blockNext();
},
});
};
blockNext();
This code finds unblocked users, blocks them with the blockAllUsers
API query (which you'll create in a moment), and then displays a notification with the number of users unblocked. There are a few more things to note:
- The
i
variable is the index of the current user. This will be used in theblockAllUsers
query to block the user. additionalScope
allows you to pass parameters to your REST query. In this example, it passes thei
variable to theblockAllUsers
.utils.showNotification
is a built-in JavaScript method provided by Retool. You can read more about it and other methods in our JavaScript API Reference.
Create a query to block all users
Next, create another PATCH query and name it blockAllUsers
. Set the endpoint slug to {{ getUsers.data[i].id }}
, and set blocked
to true
in the JSON body. Make sure to save the query.
This query uses the i
value passed from the JavaScript query to unblock the appropriate user ID.
After you write the query, open the peopleListScreen screen and select the Interface User Lock action. Click + New in the Actions section. This creates a default trigger action. Select this action, then:
- Set the Text field to Block all.
- Set the Query to the
blockAll
JavaScript query.
Add functionality to allow all users
You can add functionality to allow all users by duplicating what you just created and swapping the blocked logic to unblock users. Copy the code below to create the JavaScript query to unblock all users.
var users = getUsers.data;
const blockedUsers = users
.map((user, index) => [user, index])
.filter(([user]) => user.blocked);
let unblockIndex = 0;
const unblockNext = () => {
// Notify and quit when finished
if (unblockIndex >= blockedUsers.length) {
utils.showNotification({
title: "Success",
description: "Successfully unblocked " + blockedUsers.length + " users.",
notificationType: "success",
duration: 3,
});
// Update table after queries finish
getUsers.trigger();
return;
}
// Get next blocked user and unblock them
const [blockedUser, index] = blockedUsers[unblockIndex];
unblockAllUsers.trigger({
additionalScope: { i: index },
onSuccess: function () {
unblockIndex++;
unblockNext();
},
});
};
unblockNext();
Wrap up
You've now finished your app and completed the tutorial.
You can test your knowledge below or see the wrap up page for additional resources.