Interface Tutorial

This tutorial will teach you how to build an interface in Appian, working in both Design Mode and Expression Mode. Completing this tutorial will enable you to move on to the Process Model Tutorial.

Create the Appian Tutorial Application

The Appian Tutorial application is used throughout Appian tutorials. If you have already created the tutorial application, skip the steps in this section.

To begin with, we need to create an application to contain our design objects.

We will be creating the Appian Tutorial application for this tutorial. All of Appian's tutorials use the Appian Tutorial application as the reference application. This means that, once you complete this tutorial, you can reuse this application as you work through the other tutorials.

To create the Appian Tutorial application:

  1. Log in to Appian Designer (for example, myappiansite.com/suite/design).
  2. Click New Application.
  3. In the Create New Application dialog, configure the following properties:

    Property Description
    Name Enter Appian Tutorial.
    Description Leave blank. It's normally a best practice to add descriptions to all design objects. However, to save a little time, we're skipping describing how to add descriptions during this tutorial.
    Application Prefix Retain the default prefix, AT, which Appian constructs using the initial characters of each word you entered in the Name parameter. We'll be following the recommended naming standard, and using this short unique prefix whenever we name an object in this application.
  4. Click Create.
  5. In the Review Application Security dialog, configure the temporary security for the application:

    User or Group Permission Level
    Default (All Other Users) group Select Viewer in the Permission Level dropdown list.
    Your user Select Administrator in the Permission Level dropdown list.

    We're granting permissions directly to your user on a temporary basis. It's a best practice to configure security using groups, rather than individuals, so later in this tutorial, we'll be setting the application security using groups.

    The security of the application object is unrelated to the security of each of the objects contained within the application. This means that you will need to set security permissions for every object in an application in addition to the application object itself. For more information about security permissions for the application object, see Application Security.

    The application view appears.

    screenshot of the application view

    Right now, the application is empty. Each design object that you create during the course of this tutorial will appear in this list and automatically be associated with the tutorial application.

Add groups to the application

If you created the Appian Tutorial application in a previous tutorial, skip the steps in this section.

One of the first things that you need to do for each new application is to create at least two groups: one for the users of the application and one for the application's administrators. Groups are important building blocks of an application, because they allow you to organize users and assign permissions to the groups of users as you add objects.

Let's create two groups for this application so that we can add security as we go along:

  • AT Administrators
  • AT Users

To create these groups:

  1. In the application view, click NEW > Group.
  2. In the Create Group dialog, configure the following properties:
    • For Name, enter AT Administrators.
    • For Group Members, enter your username. We're adding you to these groups so you'll have permissions to create and modify objects in this tutorial.
  3. Leave all other default settings.
  4. Click CREATE.
  5. In the Review Group Security dialog, give yourself permissions to view and edit the group:
    • Click Add Users or Groups.
    • For Users or Groups, enter your username.
    • For Permission Level, leave the default Administrator value.
    • Click SAVE.
  6. Repeat these steps, using AT Users as the Name value.

screenshot of the application view containing two groups

Learn more about managing groups and users on the Group Management page.

Add security to the application

If you created the Appian Tutorial application in a previous tutorial, skip the steps in this section.

We should address the security of the application before we move on. At the beginning of this tutorial, you assigned yourself specific permissions to the application. However, Appian recommends configuring security using groups, rather than individuals for better maintainability.

Now that we've created the groups we need, we'll grant the following security permissions:

Group Permissions Result
AT Users Viewer Members of this group can see the application.
AT Administrators Administrator Members of this group are administrators of the application.

To add security to the application:

  1. In the application view, open the settings menu , then click Application Security. screenshot of the application view and settings menu, focused on the Application Security button
  2. In the Application Security dialog, set the Default (All Other Users) permissions to No Access.
  3. Click Add User or Group, then add permissions for the groups as described in the table above.
  4. Click delete icon next to your individual permissions to remove them.
  5. Click SAVE CHANGES. screenshot of the application security dialog

Create an Interface

To start, we will create an interface named expenseReportForm, and store it in the Examples folder:

  1. Open the Appian Tutorial application.
  2. Click New, and choose Interface.
  3. In the Create Interface dialog, complete the following fields:
    • Leave Create from Scratch selected.
    • Enter expenseReportForm in the Name field.
    • For Save In, use the picker to select the Examples folder.
  4. Click Create & Edit.

The newly created interface will open in a new tab by default. If you don't see a new tab, check your browser to see if you have pop-ups enabled.

Create Rule Inputs

Each form input saves its value into a variable, so let's add the variables. From the RULE INPUTS pane on the right, create rule inputs by clicking New Interface Input (+ button):

  • expenseItem (Text)
  • expenseDate (Date)
  • expenseAmount (Number (Decimal))
  • cancel (Boolean)

images/sail_tutorial/

Add Components to the Interface

In this section, we'll be adding components to our interface in Design Mode. We'll start by choosing a layout, then adding a few components to it:

  1. From the templates panel on the right, under the FORMS section, choose One Column Form.

    images/sail_tutorial/

  2. From the EDIT view, click on the title Form to select the Form Layout.
  3. From the COMPONENT CONFIGURATION pane on the right, replace the Label field value with Submit Expense Report.

    images/sail_tutorial/

  4. Delete both Section layouts by clicking on them to select them, then from the context menu choose Delete.

    images/sail_tutorial/

    • You should be left with nothing but the form layout and the cancel and submit buttons.

    SAIL_Tutorial_Cleared_Form

  5. From the COMPONENT PALETTE on the left, in the INPUTS section, drag a TEXT component, a DATE component, and a DECIMAL component into the Form Layout.

    images/sail_tutorial/

Configure Each Component

Now that we have the components, let's configure them.

  1. Click on the Text component to select it.
  2. From the COMPONENT CONFIGURATION pane on the right, change the following parameters:
    • For Label enter: Expense Item
    • For Display Value select ri!expenseItem
    • For Save Input To select ri!expenseItem
    • Check Required.

    images/sail_tutorial/

  3. Follow the same steps for the Date field and change the following parameters:
    • For Label enter: Expense Date
    • For Display Value and Save Input To, select ri!expenseDate
    • Check Required.
  4. Follow the same steps for the Decimal field and change the following parameters:
    • For Label enter: Expense Amount
    • For Display Value and Save Input To, select ri!expenseAmount
    • Check Required.
  5. You should see:

    images/sail_tutorial/

Click SAVE. Keep this window open so you can quickly modify the interface as we continue through the following sections.

Conditionally Show Interface Components

A common design requirement is to only display a component based on a condition. Because interfaces are defined using expressions, the full expression library can be used to add dynamic behavior to the interface. For this example, we'll add a paragraph component for entering comments and we will only display it when the expense amount is greater than $100.

  1. From the RULE INPUTS pane on the right, add a new input named comments of type Text.
  2. From the COMPONENT PALETTE on the left, in the INPUTS section, drag a PARAGRAPH component into the form beneath the Expense Amount component.

    images/sail_tutorial/

  3. Change the Label to Comments, set Display Value and Save Input To to the comments input, and make the field required by checking Required.
  4. Under Visibility, check Only show when …, then click Edit Condition.

    images/sail_tutorial/

  5. In the Visibility (Boolean) dialog, enter: ri!expenseAmount > 100

    images/sail_tutorial/

  6. Click OK to close the expression box.

Let's test the conditional display. Enter 101 in the Expense Amount field and click out of the field, or press the Enter key to see the paragraph component displayed.

images/sail_tutorial/

Selecting Hidden Components

Up until now you've been able to select components simply by clicking on them. However, when a component is conditionally visible, you may not be able to see it in order to click on it. Another way you can select it would be from the interface navigation hidden in the right-hand panel. Simply drag the panel to expand it.

nav_highlight

Be sure to save your interface before continuing.

Add a Validation

You can also configure validations for the interface by adding them directly to the expression. For example, let’s add a custom validation to our form that only allows users to enter up to 100 characters in the Comments field. To do this,

  1. Select the Comments paragraph component.
  2. From the COMPONENT CONFIGURATION pane, click the Edit as Expression icon to the right of the Validations field.

    images/sail_tutorial/

  3. Enter the following expression in the Validations (List of Text String) expression box:

    1
    
    if(len(ri!comments)<=100, null, "Your text has exceeded 100 characters")
    

    SAIL_Tutorial_Comment_Validation_Expression

  4. Click OK to close the expression box.

By modifying this, you can create a variety of other validations based on the content added to the "Comments" field. And since the validations parameter is an array, you can add multiple validations.

To test out the validation, enter more than 100 characters in the Comments field and click out of the field; you should your validation message.

SAIL_Tutorial_Comment_Validation_Message

Add a Reusable Component to Your Interface

In this section, we'll learn about reusability and how interface components can be represented with the Appian expression language.

There are many cases where you'll want to reuse part or all of an interface. For example, you may have several forms that have a conditional Comments field. Rather than re-create it on every interface we can move that paragraph field into a new interface object and simply call it, which is what we're going to do.

First we'll want to get the expression that represents the Comments field.

  1. Select the Comments field, then from the COMPONENT CONFIGURATION pane, click the Edit as Expression button.

    images/sail_tutorial/

    • You should now see the expression to copy.

      SAIL_Tutorial_Edit_Icon_Header_Expression

  2. From the application contents view of the Appian Tutorial application, create a new interface called enterComments and save it in the Examples folder.

  3. Add the following inputs to the new enterComments interface.
    • showWhen (Boolean)
    • labelPosition (Text)
    • readOnly (Boolean)
    • required (Boolean)
    • commentValue (Text)
    • commentSaveInto (Text Array)
  4. Drag a PARAGRAPH component and drop it onto the EDIT view.

  5. Select the Paragraph component and from the COMPONENT CONFIGURATION pane, click the Edit as Expression button.

  6. Replace the contents of the expression with the Comments field expression, then make the below, highlighted changes to the expression:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    a!paragraphField(
    label: "Comments",
    labelPosition: `ri!labelPosition`,
    value: `ri!commentValue`,
    saveInto: `ri!commentSaveInto`,
    refreshAfter: "UNFOCUS",
    showWhen: `ri!showWhen`,
    required: `ri!required`,
    height: "MEDIUM",
    !  readOnly: ri!readOnly,
    validations: if(len(ri!commentSaveInto)<=100, null, "Your text has exceeded 100 characters")
    )
    
  7. Click OK.

  8. Save the interface.

Return to the the Submit Expense Report (expenseReportForm) interface. Now you will modify this interface to call the new one you just created.

  1. Select the Comments field and from the COMPONENT CONFIGURATION pane, click the Edit as Expression button.

  2. Replace the existing expression with the following:

    1
    2
    3
    4
    5
    6
    7
    8
    
    rule!enterComments(
      showWhen: ri!expenseAmount > 100,
      labelPosition: "ABOVE",
      readOnly: false,
      required: true,
      commentValue: ri!comments,
      commentSaveInto: ri!comments
    )
    
  3. Click OK.

You should see the following:

images/sail_tutorial/

Note that your Comments field is now calling enterComments.

Make Your Interface Conditionally Read-Only

In this section we'll learn more about reusability, dynamic interface behavior, interface testing, and working in Expression Mode.

Now that we have a form to submit an expense report, we will need an interface so that an approver can review the expense report. The only difference between interfaces is that the one for the approval will need to be read-only and contain an additional input so they can approve or reject the expense report.

First, we'll add the new field for approval.

  1. Add the following inputs to the interface.
    • step (Text)
    • approve (Boolean)
  2. From the SELECTION section of the palette, drag a RADIO BUTTONS component beneath the Comments field.
  3. Select Radio Buttons.
  4. Set the following paramaters:
    • Label Position: HIDDEN
    • Selected Value: ri!approve
    • Save Selection To: ri!approve
    • Required
  5. Under Choice Labels, click List of Text.
    • Enter Approve for the first option.
    • Enter Reject for the second option.
    • Click the Radio Buttons back link.

      images/sail_tutorial/

  6. Under Choice Values, click List of Any Type.
    • Click 1, then replace that value with true.
    • Click OK.
    • Click 2, then replace that value with false.
    • Click OK.

Now, to configure the conditional requiredness of the fields click </> EXPRESSION MODE from the title bar. This replaces the Component Palette with the Interface Definition, where you can see the entire expression that defines the interface.

SAIL_Tutorial_Expression_View_Button.png

In this mode you'll add two local variables, which are interface-specific values. Local variables are initialized when the interface loads, so next we'll put the entire interface definion into the a!localVariables() function and add the local variables.

  1. Modify the interface definition by making the below, highlighted changes to the expression:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    
    +    a!localVariables(
    +      local!readOnly: ri!step="APPROVAL",
    +      local!labelPosition: if(local!readOnly, "ADJACENT", "ABOVE"),
          a!formLayout(
            label: "Submit Expense Report",
            contents: {
              a!textField(
                label: "Expense Item",
                labelPosition: "ABOVE",
                value: ri!expenseItem,
                saveInto: ri!expenseItem,
                refreshAfter: "UNFOCUS",
                required: true,
                validations: {},
                align: "LEFT"
              ),
              a!dateField(
                label: "Expense Date",
                labelPosition: "ABOVE",
                value: ri!expenseDate,
                saveInto: ri!expenseDate,
                required: true,
                validations: {},
                align: "LEFT"
              ),
              a!floatingPointField(
                label: "Expense Amount",
                labelPosition: "ABOVE",
                value: ri!expenseAmount,
                saveInto: ri!expenseAmount,
                refreshAfter: "UNFOCUS",
                required: true,
                validations: {},
                align: "LEFT"
              ),
              rule!enterComments(
                showWhen: ri!expenseAmount > 100,
                labelPosition: "ABOVE",
                readOnly: false,
                required: true,
                commentValue: ri!comments,
                commentSaveInto: ri!comments
              ),
              a!radioButtonField(
                labelPosition: "COLLAPSED",
                choiceLabels: {"Approve", "Reject"},
                choiceValues: {true, false},
                value: ri!approve,
                saveInto: ri!approve,
                required: true
              )
            },
            buttons: a!buttonLayout(
              primaryButtons: {
                a!buttonWidget(
                  label: "Submit",
                  style: "PRIMARY",
                  submit: true
                )
              },
              secondarybuttons: {
                a!buttonWidget(
                  label: "Cancel",
                  style: "SECONDARY",
                  value: true,
                  saveInto: ri!cancel,
                  submit: true,
                  validate: false
                )
              }
            )
          )
    + )
    
  2. Use the new local!readOnly variable to make each component conditionally read-only and optional when it is in read-only mode. Use the new local!labelPosition to control each component's label position (except where the label position is COLLAPSED). Modify your expression with the following:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    
    a!localVariables(
      local!readOnly: ri!step="APPROVAL",
      local!labelPosition: if(local!readOnly, "ADJACENT", "ABOVE"),
      a!formLayout(
        label: "Submit Expense Report",
        contents: {
          a!textField(
            label: "Expense Item",
            labelPosition: `local!labelPosition`,
            value: ri!expenseItem,
            saveInto: ri!expenseItem,
            refreshAfter: "UNFOCUS",
            required: `not(local!readOnly)`,
    +       readOnly: local!readOnly,
            validations: {},
            align: "LEFT"
          ),
          a!dateField(
            label: "Expense Date",
            labelPosition: `local!labelPosition`,
            value: ri!expenseDate,
            saveInto: ri!expenseDate,
            required: `not(local!readOnly)`,
    +       readOnly: local!readOnly,
            validations: {},
            align: "LEFT"
          ),
          a!floatingPointField(
            label: "Expense Amount",
            labelPosition: `local!labelPosition`,
            value: ri!expenseAmount,
            saveInto: ri!expenseAmount,
            refreshAfter: "UNFOCUS",
            required: `not(local!readOnly)`,
    +       readOnly: local!readOnly,
            validations: {},
            align: "LEFT"
          ),
          rule!enterComments(
            showWhen: ri!expenseAmount > 100,
            labelPosition: `local!labelPosition`,
            readOnly: `local!readOnly`,
            required: `not(local!readOnly)`,
            commentValue: ri!comments,
            commentSaveInto: ri!comments
          ),
          a!radioButtonField(
            labelPosition: "COLLAPSED",
            choiceLabels: {"Approve", "Reject"},
            choiceValues: {true, false},
            value: ri!approve,
            saveInto: ri!approve,
            required: true
          )
        },
        buttons: a!buttonLayout(
          primaryButtons: {
            a!buttonWidget(
              label: "Submit",
              style: "PRIMARY",
              submit: true
            )
          },
          secondarybuttons: {
            a!buttonWidget(
              label: "Cancel",
              style: "SECONDARY",
              value: true,
              saveInto: ri!cancel,
              submit: true,
              validate: false
            )
          }
        )
      )
    )
    
  3. Only display the radio button when on the approval step by modifying your expression with the following:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    
    a!localVariables(
      local!readOnly: ri!step="APPROVAL",
      local!labelPosition: if(local!readOnly, "ADJACENT", "ABOVE"),
      a!formLayout(
        label: "Submit Expense Report",
        contents: {
          a!textField(
            label: "Expense Item",
            labelPosition: local!labelPosition,
            value: ri!expenseItem,
            saveInto: ri!expenseItem,
            refreshAfter: "UNFOCUS",
            required: not(local!readOnly),
            readOnly: local!readOnly,
            validations: {},
            align: "LEFT"
          ),
          a!dateField(
            label: "Expense Date",
            labelPosition: local!labelPosition,
            value: ri!expenseDate,
            saveInto: ri!expenseDate,
            required: not(local!readOnly),
            readOnly: local!readOnly,
            validations: {},
            align: "LEFT"
          ),
          a!floatingPointField(
            label: "Expense Amount",
            labelPosition: local!labelPosition,
            value: ri!expenseAmount,
            saveInto: ri!expenseAmount,
            refreshAfter: "UNFOCUS",
            required: not(local!readOnly),
            readOnly: local!readOnly,
            validations: {},
            align: "LEFT"
          ),
          rule!enterComments(
            showWhen: ri!expenseAmount > 100,
            labelPosition: local!labelPosition,
            readOnly: local!readOnly,
            required: not(local!readOnly),
            commentValue: ri!comments,
            commentSaveInto: ri!comments
          ),
          a!radioButtonField(
            labelPosition: "COLLAPSED",
            choiceLabels: {"Approve", "Reject"},
            choiceValues: {true, false},
            value: ri!approve,
            saveInto: ri!approve,
            required: true`,`
    +       showWhen: local!readOnly
          )
        },
        buttons: a!buttonLayout(
          primaryButtons: {
            a!buttonWidget(
              label: "Submit",
              style: "PRIMARY",
              submit: true
            )
          },
          secondarybuttons: {
            a!buttonWidget(
              label: "Cancel",
              style: "SECONDARY",
              value: true,
              saveInto: ri!cancel,
              submit: true,
              validate: false
            )
          }
        )
      )
    )
    
  4. Hide the cancel button on the approval step by modifying your expression with the following:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    
    a!localVariables(
      local!readOnly: ri!step="APPROVAL",
      local!labelPosition: if(local!readOnly, "ADJACENT", "ABOVE"),
      a!formLayout(
        label: "Submit Expense Report",
        contents: {
          a!textField(
            label: "Expense Item",
            labelPosition: local!labelPosition,
            value: ri!expenseItem,
            saveInto: ri!expenseItem,
            refreshAfter: "UNFOCUS",
            required: not(local!readOnly),
            readOnly: local!readOnly,
            validations: {},
            align: "LEFT"
          ),
          a!dateField(
            label: "Expense Date",
            labelPosition: local!labelPosition,
            value: ri!expenseDate,
            saveInto: ri!expenseDate,
            required: not(local!readOnly),
            readOnly: local!readOnly,
            validations: {},
            align: "LEFT"
          ),
          a!floatingPointField(
            label: "Expense Amount",
            labelPosition: local!labelPosition,
            value: ri!expenseAmount,
            saveInto: ri!expenseAmount,
            refreshAfter: "UNFOCUS",
            required: not(local!readOnly),
            readOnly: local!readOnly,
            validations: {},
            align: "LEFT"
          ),
          rule!enterComments(
            showWhen: ri!expenseAmount > 100,
            labelPosition: local!labelPosition,
            readOnly: local!readOnly,
            required: not(local!readOnly),
            commentValue: ri!comments,
            commentSaveInto: ri!comments
          ),
          a!radioButtonField(
            labelPosition: "COLLAPSED",
            choiceLabels: {"Approve", "Reject"},
            choiceValues: {true, false},
            value: ri!approve,
            saveInto: ri!approve,
            required: true,
            showWhen: local!readOnly
          )
        },
        buttons: a!buttonLayout(
          primaryButtons: {
            a!buttonWidget(
              label: "Submit",
              style: "PRIMARY",
              submit: true
            )
          },
          secondarybuttons: {
            a!buttonWidget(
              label: "Cancel",
              style: "SECONDARY",
              value: true,
              saveInto: ri!cancel,
              submit: true,
              validate: false`,`
    +         showWhen: not(local!readOnly)
            )
          }
        )
      )
    )
    
  5. Change the form title based on the step by modifying your expression with the following:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    
    a!localVariables(
      local!readOnly: ri!step="APPROVAL",
      local!labelPosition: if(local!readOnly, "ADJACENT", "ABOVE"),
      a!formLayout(
        label: `if(local!readOnly, "Approve Expense Report", "Submit Expense Report")`,
        contents: {
          a!textField(
            label: "Expense Item",
            labelPosition: local!labelPosition,
            value: ri!expenseItem,
            saveInto: ri!expenseItem,
            refreshAfter: "UNFOCUS",
            required: not(local!readOnly),
            readOnly: local!readOnly,
            validations: {},
            align: "LEFT"
          ),
          a!dateField(
            label: "Expense Date",
            labelPosition: local!labelPosition,
            value: ri!expenseDate,
            saveInto: ri!expenseDate,
            required: not(local!readOnly),
            readOnly: local!readOnly,
            validations: {},
            align: "LEFT"
          ),
          a!floatingPointField(
            label: "Expense Amount",
            labelPosition: local!labelPosition,
            value: ri!expenseAmount,
            saveInto: ri!expenseAmount,
            refreshAfter: "UNFOCUS",
            required: not(local!readOnly),
            readOnly: local!readOnly,
            validations: {},
            align: "LEFT"
          ),
          rule!enterComments(
            showWhen: ri!expenseAmount > 100,
            labelPosition: local!labelPosition,
            required: not(local!readOnly),
            readOnly: local!readOnly,
            commentValue: ri!comments,
            commentSaveInto: ri!comments
          ),
          a!radioButtonField(
            labelPosition: "COLLAPSED",
            choiceLabels: {"Approve", "Reject"},
            choiceValues: {true, false},
            value: ri!approve,
            saveInto: ri!approve,
            required: true,
            showWhen: local!readOnly
          )
        },
        buttons: a!buttonLayout(
          primaryButtons: {
            a!buttonWidget(
              label: "Submit",
              style: "PRIMARY",
              submit: true
            )
          },
          secondarybuttons: {
            a!buttonWidget(
              label: "Cancel",
              style: "SECONDARY",
              value: true,
              saveInto: ri!cancel,
              submit: true,
              validate: false,
              showWhen: not(local!readOnly)
            )
          }
        )
      )
    )
    

Now let's test the read-only behavior of the interface.

  1. Click TEST from the title bar. This pulls up the Test Inputs dialog. Enter the Value for the following inputs:
    • expenseItem (Text): Team Lunch
    • expenseDate (Date): 05/03/2017
    • expenseAmount (Number (Decimal)): 120.87
    • comments (Text): Team lunch for 6 people.
    • step (Text): APPROVAL

    SAIL_Tutorial_Test_Read_Only.png

  2. Click Test Interface to check out the new read-only behavior.

You should see the following:

images/sail_tutorial/

Congratulations! You're ready to move on to other tutorials.

Open in Github Built: Mon, Sep 27, 2021 (12:29:11 PM)

On This Page

FEEDBACK