Grid Tutorial

The walkthrough on this page will help you create your first read-only grid to display on an interface. It starts with a basic grid that displays data from a record type and builds in complexity as you progress.

Use the data provided to understand how the configurations work. Then, try it with your own data. Keep in mind, the final configurations will need to change if your data has different field names.

See Also

Paging Grid: Configures a read-only grid with selection and paging controls. This tutorial focuses on configuring this grid.
Editable Grid: Organizes input components in a tabular layout.

The content below assumes a basic familiarity with expressions, and focuses more on the specifics of displaying and modifying grid components in an Interface.

Create the Appian Tutorial Application

The Appian Tutorial application is used to contain the design objects created while working through this tutorial.

The tutorial application only needs to be created once. If you have already created the tutorial application, skip the steps below.

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 Name field, type Appian Tutorial.
  4. Optionally, in the Description field, add a short description.
  5. Click Create.

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

Create a Basic Grid

The steps below show how to create a basic paging grid using data from a record type. Then, we'll show you how to align the column values and format the data. Finally, we'll show you how to add a default filter to display only a certain set of data in the grid.

First we'll need a record type to query data from. Let's use the process-backed record from the Record Tutorials.

See also: Create Process-Backed Records

You already created one instance of this process in the Record Tutorial, but you may want to create some additional instances so that you can sort and page your data in the grid. Here are the relevant fields from the instances that are used in the remainder of this tutorial:

expenseItem expenseAmount expenseDate
Plane ticket to St. Louis 200 4/16/2014
Lunch meeting 45.50 4/24/2014
Registration fee 245 4/1/2014
Conference call with client 5.75 4/15/2014
Purchased training manual for seminar 29.99 4/1/2014
Rental car expenses for trip to client HQ 115 4/16/2014
Hotel room expenses for trip to client HQ 99.95 4/16/2014

To start, we will create a constant called EXPENSE_REPORT_RECORD, and store it in the Examples folder:

  1. Navigate to the application contents view of the Appian Tutorial application (if needed).
  2. Click New, and then click Constant.
  3. In the Create Constant dialog, complete the following fields:
    • Leave Create from Scratch selected
    • For Name, type EXPENSE_REPORT_RECORD
    • For Type, select Record Type
    • For Value select Expense Report
    • For Save In, use the picker to select the Examples folder
  4. Click Create.

This will allow us to query the data that will be displayed in the grid.

Next, let's create an interface called GT_expenseReportGrid, and store it in the Examples folder:

  1. Navigate to the application contents view of the Appian Tutorial application (if needed).
  2. Click New, and then click Interface.
  3. In the Create Interface dialog, complete the following fields:
    • Leave Create from Scratch selected
    • For Name, type GT_expenseReportGrid
    • For Save In, use the picker to select the Examples folder
  4. Click Create & Edit.
    • The interface object will open in a new browser tab.

Now let's create the grid using the Report Builder. Open the interface object and select the Report Builder from the template options.

In the Source Constant field, select your EXPENSE_REPORT_RECORD constant. You should see the following:

Notice that the grid has the expenseItem and expenseAmount fields selected. The report builder automatically selects up to three text fields and up to three number fields by default. The Preview at the bottom shows what the resulting grid will look like based on the provided configurations.

Now let's add the expenseDate field so that it is also displayed in the grid. In the Add a field… dropdown, select the expenseDate field and click Add Field. You should see the following:

Next, let's change the display name of each field so that the column headers aren't the names of the fields. For each field, click the Change display name link and change the names to Item, Amount, and Date respectively. The column headers in the Preview will update to match these values.

Finally, let's change the default sort so that the most recent expense items are shown first. In the Default Sort Field dropdown, select the Date column and uncheck the Ascending box. You should see the following:

Now we're done configuring our grid. Click the Generate button to generate the expression for the grid that is displayed in the Preview. You should see the following expression in the expression view:

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
load(
  local!pagingInfo: a!pagingInfo(
    startIndex: 1,
    batchSize: 20,
    sort: a!sortInfo(
      field: "expenseDate",
      ascending: false
    )
  ),
  with(
    local!datasubset: queryrecord(
      cons!EXPENSE_REPORT_RECORD,
      a!query(
        selection: a!querySelection(columns: {
          a!queryColumn(field: "expenseItem"),
          a!queryColumn(field: "expenseAmount"),
          a!queryColumn(field: "expenseDate"),
        }),
        pagingInfo: local!pagingInfo
      )
    ),
    a!gridField(
      totalCount: local!datasubset.totalCount,
      columns: {
        a!gridTextColumn(
          label: "Item",
          field: "expenseItem",
          data: index(local!datasubset.data, "expenseItem", null)
        ),
        a!gridTextColumn(
          label: "Amount",
          field: "expenseAmount",
          data: index(local!datasubset.data, "expenseAmount", null)
        ),
        a!gridTextColumn(
          label: "Date",
          field: "expenseDate",
          data: index(local!datasubset.data, "expenseDate", null)
        ),
      },
      value: local!pagingInfo,
      saveInto: local!pagingInfo
    )
  )
)

This expression results in a dynamic grid with paging and sorting. Now let's take a look at how the paging and sorting works.

Paging and Sorting Configurations

In the expression above, the paging configuration is stored in a load() variable called local!pagingInfo. Next, the data is then queried from the record type using queryrecord(). We pass local!pagingInfo as its second parameter since it determines how many items to return and in what order. Finally, we store the result of the query into a with() variable called local!datasubset. This data is then displayed in the different columns of the grid.

See also: load(), with(), queryrecord()

Notice that local!pagingInfo is also used as the value for the grid. This is how the grid knows what page you are currently on (startIndex), the maximum number of rows that can be on that page (batchSize), and the column header that the data is sorted by (sort). According to the default value that we set for local!pagingInfo, the grid will start on the first page, show a maximum of 20 items, and sort by the expenseDate field in descending order.

In addition to the default paging configuration, the user who is viewing the grid can also interact with it to page and sort it. When the user interacts with the grid, the new paging configuration will be saved into local!pagingInfo because we have specified it as the saveInto parameter. This means that when the user clicks on an arrow in paging toolbar, the start index is updated with the requested page. Similarly, when the user clicks on a column header, the sort is updated with the field that corresponds to that column.

When the local!pagingInfo is updated, the query in local!datasubset is executed based on the new paging configuration. The grid then displays that new data and indicates the new paging configuration either by updating the paging toolbar or column headers, depending on the user's interaction.

See also: Enabling User Interaction

Align the Column Values

Now that you have a basic grid, let's align the "Amount" and "Date" columns to the right. By default, all columns are aligned to the left. To do so, simply update these columns and add alignment: "RIGHT". Modify your expression in the design pane with the following (the grey text indicates what parts of the expression are the same as the before):

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
load(
  local!pagingInfo: a!pagingInfo(
    startIndex: 1,
    batchSize: 20,
    sort: a!sortInfo(
      field: "expenseDate",
      ascending: false
    )
  ),
  with(
    local!datasubset: queryrecord(
      cons!EXPENSE_REPORT_RECORD,
      a!query(
        selection: a!querySelection(columns: {
          a!queryColumn(field: "expenseItem"),
          a!queryColumn(field: "expenseAmount"),
          a!queryColumn(field: "expenseDate"),
        }),
        pagingInfo: local!pagingInfo
      )
    ),
    a!gridField(
      totalCount: local!datasubset.totalCount,
      columns: {
        a!gridTextColumn(
          label: "Item",
          field: "expenseItem",
          data: index(local!datasubset.data, "expenseItem", null)
        ),
        a!gridTextColumn(
          label: "Amount",
          field: "expenseAmount",
          data: index(local!datasubset.data, "expenseAmount", null)`,`
+         alignment: "RIGHT"
        ),
        a!gridTextColumn(
          label: "Date",
          field: "expenseDate",
          data: index(local!datasubset.data, "expenseDate", null)`,`
+         alignment: "RIGHT"
        ),
      },
      value: local!pagingInfo,
      saveInto: local!pagingInfo
    )
  )
)

You should see the following:

The "Amount" and "Date" columns are now right-aligned, while the other column remains left-aligned by default.

Format the Displayed Data

Until this point, we have been displaying the results of the query as is. You can also format the data that displays while still preserving the ability to sort on that field. First let's reformat the "Amount" and "Date" columns. Modify your expression in the design pane 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
load(
  local!pagingInfo: a!pagingInfo(
    startIndex: 1,
    batchSize: 20,
    sort: a!sortInfo(
      field: "expenseDate",
      ascending: false
    )
  ),
  with(
    local!datasubset: queryrecord(
      cons!EXPENSE_REPORT_RECORD,
      a!query(
        selection: a!querySelection(columns: {
          a!queryColumn(field: "expenseItem"),
          a!queryColumn(field: "expenseAmount"),
          a!queryColumn(field: "expenseDate"),
        }),
        pagingInfo: local!pagingInfo
      )
    ),
    a!gridField(
      totalCount: local!datasubset.totalCount,
      columns: {
        a!gridTextColumn(
          label: "Item",
          field: "expenseItem",
          data: index(local!datasubset.data, "expenseItem", null)
        ),
        a!gridTextColumn(
          label: "Amount",
          field: "expenseAmount",
          data: `dollar(index(local!datasubset.data, "expenseAmount", {})),`
          /* Need to change the default to an empty list so  */
          /* that dollar() doesn't fail when there's no data */
          alignment: "RIGHT"
        ),
        a!gridTextColumn(
          label: "Date",
          field: "expenseDate",
          data: `text(index(local!datasubset.data, "expenseDate", {}), "MMM d, yyyy"),`
          /* Need to change the default to an empty list so  */
          /* that text() doesn't fail when there's no data   */
          alignment: "RIGHT"
        ),
      },
      value: local!pagingInfo,
      saveInto: local!pagingInfo
    )
  )
)

You should then see the following:

This expression uses the dollar() function to display the expenseAmount field as a dollar amount. Similarly, the text() function displays the expenseDate field with a specific format that is different from the default format for dates.

If you try sorting on one of these fields, however, you will notice that the column is sorted using the underlying data in that column, not the text version that is being displayed. This is because the sort is applied by the query itself using the field name defined in the column; the text formatting isn't done until after that data is returned. The other significant advantage of this is that the formatting is only applied on the current page, not the entire data set.

Additionally, note that we did not have to use a looping function to display the amount in currency format, nor to display the date. This is because both the dollar() and text() functions can take an array as a parameter.

Add a Default Filter

Currently, the grid displays all data for the record. Let's add a default filter so that only items that are less than $100 are displayed. To do this, we need to add a filter to our query. Modify your expression in the design pane 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
load(
  local!pagingInfo: a!pagingInfo(
    startIndex: 1,
    batchSize: 20,
    sort: a!sortInfo(
      field: "expenseDate",
      ascending: false
    )
  ),
  with(
    local!datasubset: queryrecord(
      cons!EXPENSE_REPORT_RECORD,
      a!query(
        selection: a!querySelection(columns: {
          a!queryColumn(field: "expenseItem"),
          a!queryColumn(field: "expenseAmount"),
          a!queryColumn(field: "expenseDate"),
        }),
+        filter: a!queryFilter(
+          field: "expenseAmount",
+          operator: "<",
+          value: 100
+        ),
        pagingInfo: local!pagingInfo
      )
    ),
    a!gridField(
      totalCount: local!datasubset.totalCount,
      columns: {
        a!gridTextColumn(
          label: "Item",
          field: "expenseItem",
          data: index(local!datasubset.data, "expenseItem", null)
        ),
        a!gridTextColumn(
          label: "Amount",
          field: "expenseAmount",
          data: dollar(index(local!datasubset.data, "expenseAmount", null)),
          /* Need to change the default to an empty list so  */
          /* that dollar() doesn't fail when there's no data */
          alignment: "RIGHT"
        ),
        a!gridTextColumn(
          label: "Date",
          field: "expenseDate",
          data: text(index(local!datasubset.data, "expenseDate", null), "MMM d, yyyy"),
          /* Need to change the default to an empty list so  */
          /* that text() doesn't fail when there's no data   */
          alignment: "RIGHT"
        ),
      },
      value: local!pagingInfo,
      saveInto: local!pagingInfo
    )
  )
)

You should see the following:

You can also add a dynamic filter so that the user can choose how to filter the data as they view the grid. This can be done using a dropdown when you want to restrict how the data can be filtered or a text field when you want the user to be able to search the data using free-form text.

See also: Filter the Data in a Grid

Additional Grid Design Patterns

There are a number of other design elements you can incorporate into your grid, such as selecting rows, using grid links to show more details, and using grid links to edit data. These and other patterns can be found on our interface recipes page.

See also: Display Data with CDT Fields in a Grid
Format Data in a Grid
Show Calculated Columns in a Grid
Conditionally Hide a Column in a Grid
Select Rows in a Grid
Use Links in a Grid to Show More Details About an Object
Use Links in a Grid to Show More Details and Edit Data

FEEDBACK