Using JavaScript to write expressions in App Studio - AWS App Studio

AWS App Studio is in preview and is subject to change.

Using JavaScript to write expressions in App Studio

In AWS App Studio, you can use JavaScript expressions to dynamically control the behavior and appearance of your applications. Single-line JavaScript expressions are written within double curly braces, {{ }}, and can be used in various contexts such as automations, UI components, and data queries. These expressions are evaluated at runtime and can be used to perform calculations, manipulate data, and control application logic.

App Studio provides native support for three JavaScript open source libraries: Luxon, UUID, Lodash as well as SDK integrations to detect JavaScript syntax and type-checking errors within your app's configurations.

Basic syntax

JavaScript expressions can include variables, literals, operators, and function calls. Expressions are commonly used to perform calculations or evaluate conditions.

See the following examples:

  • {{ 2 + 3 }} will evaluate to 5.

  • {{ "Hello, " + "World!" }} will evaluate to "Hello, World!".

  • {{ Math.max(5, 10) }} will evaluate to 10.

  • {{ Math.random() * 10 }} returns a random number (with decimals) between [0-10).

Interpolation

You can also use JavaScript to interpolate dynamic values within static text. This is achieved by enclosing the JavaScript expression within double curly braces, like the following example:

Hello {{ currentUser.firstName }}, welcome to App Studio!

In this example, currentUser.firstName is a JavaScript expression that retrieves the first name of the current user, which is then dynamically inserted into the greeting message.

Concatenation

You can concatenate strings and variables using the + operator in JavaScript, as in the following example.

{{ currentRow.FirstName + " " + currentRow.LastName }}

This expression combines the values of currentRow.FirstName and currentRow.LastName with a space in between, resulting in the full name of the current row.

Date and time

JavaScript provides various functions and objects for working with dates and times. For example:

  • {{ new Date().toLocaleDateString() }}: Returns the current date in a localized format.

  • {{ DateTime.now().toISODate() }}: Returns the current date in YYYY-MM-DD format, for use in the Date component.

Code blocks

In addition to expressions, you can also write multi-line JavaScript code blocks. Unlike expressions, code blocks do not require curly braces. Instead, you can write your JavaScript code directly within the code block editor.

Note

While expressions are evaluated and their values are displayed, code blocks are run, and their output (if any) is displayed.

Global variables and functions

App Studio provides access to certain global variables and functions that can be used within your JavaScript expressions and code blocks. For example, currentUser is a global variable that represents the currently logged-in user, and you can access properties like currentUser.role to retrieve the user's role.

Accessing UI component values

One of the powerful features of App Studio is the ability to access values from UI components within expressions. This allows for dynamic behavior and data binding between components, which builders can use to create truly interactive and data-driven applications.

The ui namespace provides read-only access to the values and properties of UI components on the same page. By referencing a component's name, you can retrieve its value or perform operations based on its state.

The following list contains the syntax for using the ui namespace to access UI component values.

  • {{ui.textInputName.value}}: Retrieve the value of a text input component named textInputName.

  • {{ui.formName.isValid}}: Check if all fields in the form named formName are valid.

  • {{ui.tableName.currentRow.columnName}}: Access the value of a specific column in the current row of a table component named tableName.

  • {{ui.tableName.selectedRows}}: Retrieve the selected rows in a table component named tableName.

For example:

  • {{ui.myTextField.value}} gives you the current value of a text input field named myTextField.

  • {{ui.userForm.isValid}} will check if all fields in a form named userForm are valid.

  • {{ui.ordersTable.currentRow.orderTotal}} will retrieve the value of the orderTotal column in the current row of a table component named ordersTable.

However, to update or manipulate the value of a component, you need to use RunComponentAction. Within expressions, component values are read-only, but you can trigger actions that modify their values. Here's an example of how you can update the value of a text input component named myInput using RunComponentAction:

RunComponentAction(ui.myInput, "setValue", "New Value")

In this example, the RunComponentAction step calls the setValue action on the myInput component, passing in the new value, New Value.

By combining the ability to read component values within expressions and update them using RunComponentAction steps, you can create dynamic and interactive user interfaces that respond to user input and data changes.

Note that the ui namespace will only show components on the current page, as components are scoped to their respective pages.

Additional examples

  • {{ui.inputText1.value.trim().length > 0}}: Check if the value of the inputText1 component, after trimming any leading or trailing whitespace, has a non-empty string. This can be useful for validating user input or enabling/disabling other components based on the input text field's value.

  • {{ui.multiSelect1.value.join(", ")}}: For a multi-select component named multiSelect1, this expression converts the array of selected option values into a comma-separated string. This can be helpful for displaying the selected options in a user-friendly format or passing the selections to another component or automation.

  • {{ui.multiSelect1.value.includes("option1")}}: This expression checks if the value option1 is included in the array of selected options for the multiSelect1 component. It returns true if option1 is selected, and false otherwise. This can be useful for conditionally rendering components or taking actions based on specific option selections.

  • {{new Date().toLocaleDateString()}}: This expression gets the current date and converts it to a localized string representation based on the user's locale settings. It can be used to display the current date in a user-friendly format or to pre-fill date fields with the current date.

  • {{new Date().toISOString()}}: This expression generates the current date in the ISO format ("2023-06-15T10:30:00.000Z"), which is the format expected by many entities and components. It can be used to pre-fill date fields with the current date or timestamp.

  • {{ui.s3Upload1.files.length > 0}}: For an Amazon S3 file upload component named s3Upload1, this expression checks if any files have been uploaded by checking the length of the files array. It can be useful for enabling/disabling other components or actions based on whether files have been uploaded.

  • {{ui.s3Upload1.files.filter(file => file.type === "image/png").length}}: This expression filters the list of uploaded files in the s3Upload1 component to only include PNG image files, and returns the count of those files. This can be helpful for validating or displaying information about the types of files uploaded.

Working with table data

The currentRow and ui.tableName.selectedRow objects provide access to table data, allowing builders to perform operations and manipulations based on the current or selected row.

Note that currentRow and ui.tableName.data have different structures. The currentRow object is based on the column mappings configured for the table, while ui.tableName.data contains the raw data from the entity.

The following list contains the syntax for working with table data.

  • {{currentRow.columnMappingName}}: Retrieve the value of the columnMappingName column for the current row in a table.

  • {{ui.tableName.selectedRow.columnMappingName}}: Retrieve the value of the columnMappingName column for the selected row in the table named tableName.

See the following examples:

  • {{currentRow.firstName + ' ' + currentRow.lastNamecolumnMapping}}: Concatenate values from multiple columns to create a new column in a table.

  • {{ { "Blocked": "🔴", "Delayed": "🟡", "On track": "🟢" }[currentRow.statuscolumnMapping] + " " + currentRow.statuscolumnMapping}}: Customize the display value of a field within a table based on the stored status value.

  • {{currentRow.colName}} or {{currentRow["First Name"]}} or {{currentRow}} or {{ui.tableName.selectedRows[0]}}: Pass the referenced row's context within a row action.

  • {{ui.tableName.selectedRows[0].columnMappingName}}: Reference the selected row's column name from other components or expressions on the same page.

Accessing automations

Automations allow you to run server-side logic and operations in App Studio. You can use expressions to process data, generate dynamic values, and incorporate results from previous actions.

Accessing automation parameters

You can pass dynamic values from UI components and other automations into automations, making them reusable and flexible. This is done using automation parameters with the params namespace as follows:

{{params.parameterName}}: Reference a value passed into the automation from a UI component or other source. For example, {{params.ID}} would reference a parameter named ID.

Manipulating automation parameters

You can use JavaScript to manipulate automation parameters. See the following examples:

  • {{params.firstName}} {{params.lastName}}: Concatenate values passed as parameters.

  • {{params.numberParam1 + params.numberParam2}}: Add two number parameters.

  • {{params.valueProvided?.length > 0 ? params.valueProvided : 'Default'}}: Check if a parameter is not null or undefined, and has a non-zero length. If true, use the provided value; otherwise, set a default value.

  • {{params.rootCause || "No root cause provided"}}: If the params.rootCause parameter is false (null, undefined, or an empty string), use the provided default value.

  • {{Math.min(params.numberOfProducts, 100)}}: Restrict the value of a parameter to a maximum value (in this case, 100).

  • {{ DateTime.fromISO(params.startDate).plus({ days: 7 }).toISO() }}: If the params.startDate parameter is "2023-06-15T10:30:00.000Z", this expression will evaluate to "2023-06-22T10:30:00.000Z", which is the date one week after the start date.

Accessing automation results from a previous action

Automations allow application to run server-side logic and operations, such as querying databases, interacting with APIs, or performing data transformations. The results namespace provides access to the outputs and data returned by previous actions within the same automation. Note the following points about accessing automation results:

  1. You can only access results of previous automation steps within the same automation.

  2. If you have actions named action1 and action2 in that order, action1 cannot reference any results, and action2 can only access results.action1.

  3. This also works in client-side actions. For example, if you have a button that triggers an automation using the InvokeAutomation action. You can then have a navigation step with a Run If condition like results.myInvokeAutomation1.fileType === "pdf" to navigate to a page with a PDF viewer if the automation indicates the file is a PDF.

The following list contains the syntax for accessing automation results from a previous action using the results namespace.

  • {{results.stepName.data}}: Retrieve the data array from an automation step named stepName.

  • {{results.stepName.output}}: Retrieve the output of an automation step named stepName.

The way you access the results of an automation step depends on the type of action and the data it returns. Different actions may return different properties or data structures. Here are some common examples:

  • For a data action, you can access the returned data array using results.stepName.data.

  • For an API call action, you may access the response body using results.stepName.body.

  • For an Amazon S3 action, you may access the file content using results.stepName.Body.transformToWebStream().

See the documentation for the specific action types you're using to understand the shape of the data they return and how to access it within the results namespace. The following list contains some examples

  • {{results.getDataStep.data.filter(row => row.status === "pending").length}}: Assuming the getDataStep is an Invoke Data Action automation action that returns an array of data rows, this expression filters the data array to include only rows where the status field is equal to pending, and returns the length (count) of the filtered array. This can be useful for querying or processing data based on specific conditions.

  • {{params.email.split("@")[0]}}: If the params.email parameter contains an email address, this expression splits the string at the @ symbol and returns the part before the @ symbol, effectively extracting the username portion of the email address.

  • {{new Date(params.timestamp * 1000)}}: This expression takes a Unix timestamp parameter (params.timestamp) and converts it to a JavaScript Date object. It assumes that the timestamp is in seconds, so it multiplies it by 1000 to convert it to milliseconds, which is the format expected by the Date constructor. This can be useful for working with date and time values in automations.

  • {{results.stepName.Body}}: For an Amazon S3 GetObject automation action named stepName, this expression retrieves the file content, which can be consumed by UI components like Image or PDF Viewer for displaying the retrieved file. Note that this expression would need to be configured in the Automation output of the automation to use in components.