Learn how to create a read-only grid with the most common configurations in about 15 minutes. After completing this tutorial, you will know how to:
This tutorial requires basic familiarity with the Appian platform. If you are brand new to Appian, head over to Appian Academy Online and explore the many, free courses available.
Before beginning this tutorial, you must first complete the Application Building Tutorial.
You must have the example, employee data set in your environment (EMPLOYEE_ENTITY
). If you do not have that example data, you must create it by completing this recipe: Use the Write to Data Store Entity Smart Service Function on an Interface.
Grids are how we display data in a tabular format (AKA a table). A table in a database has a set of fields that, when populated, become the records. A grid displays those fields as columns, and the records as rows. The Appian read-only grid understands this relationship, and is designed to handle your data in intelligent ways.
In this tutorial, you will create a grid with selection in Design Mode (the best way) and learn all the major aspects of the grid. The scenario is we've been asked to create a list of all employees that will allow selection of any number of them to be entered into a raffle. We've also been asked to prevent selection for those in the Sales department (since they're already drowning in additional compensation), but they still want those employees to show up in the list.
The interface you'll create is a variation of the Grid with Selection pattern. Component patterns are great way to get started quickly, or learn from expert designs.
AT_raffleGrid
Grid for selecting employees for the raffle.
Folder: AT Examples
(if it doesn't exist, create it by clicking the Create New Rule Folder link).
Now, from the COMPONENTS palette, drag the READ-ONLY GRID component onto your blank interface.
After dragging the grid into your interface, you can add data from the COMPONENT CONFIGURATION panel on the right.
From the DATA section, with Use query editor selected, click CREATE QUERY.
EMPLOYEE_ENTITY
.This is the query editor, which makes creating queries easy.
For our query, we only need these fields:
id
firstName
lastName
department
startDate
However, in the Fields section, you can see that all fields are selected by default. Remove the fields you don't need from the Query Results Preview.
Hover over the options menu ( ) for the title
and phoneNumber
columns, and click REMOVE.
Click GENERATE QUERY.
Your grid is now populated with the employee data from the query.
If you're just reading this tutorial, and you see the above screenshot and think, "Wait, that was too easy. I must have missed a bunch of steps somewhere." You can relax; you didn't miss anything. When you use the query editor from the context of a grid, Appian takes your query results and populates columns for you, makes them sortable, and takes a good guess as to what your column names might be. If it sees numbers or dates, it aligns them to the right for you.
Paging and sorting is something you can configure for the query, but the grid handles both natively, allowing you to change them from the COMPONENT CONFIGURATION panel.
5
.lastName
.For Order, select Ascending.
The field data from the query are passed into their respective columns automatically. The display value of every column is set with the function variable, fv!row
. This variable contains all the data for the entire row. For example, in the First Name column, the display value is fv!row.firstName
.
In this section we will remove the ID column, format the department column in italics, and conditionally change the color of the department text.
Since we don't need to see the employee's ID, let's remove it.
From the Columns section, hover over the options menu ( ) for Id (Grid Column), and click the X icon to Delete the column.
From RICH TEXT, click STYLED TEXT.
Since we don't want anyone from the Sales department entered into the raffle, let's remind the user by changing the color of "Sales" in that column.
if(fv!row.department="Sales", "SECONDARY", null)
Now, when the row evaluates, if the department in that row (fv!row.department
) is Sales
, the color will be set to "SECONDARY"
for that row, otherwise it'll be null
(the default).
When grids have selection and paging, it's good UX practice to provide a secondary display so the user can see the totality of their selection no matter what page they're on.
If you're still somewhat new to interface design in Appian, follow these directions.
Shortcut If you're familiar with interface design, here are some higher-level steps you can follow, after which you can skip to section 7:
WIDE
.user-circle
).Drag a COLUMNS component from the palette to just below the grid.
Delete one of the columns by clicking on the Delete column icon ().
Hover over the Read-only Grid selector until the component hierarchy displays, then click Column Layout.
Now that the column is selected, let's make it wider.
user-circle
into the searchbox and select this icon (), and click INSERT.And this is where we're going to leave it for now:
To setup grid selection, you only need to create a local variable to save the selection value to. In our case, we also need to pass the selected row's data to a local variable so we can display the selected employees somewhere. So, we're going to add two local variables, (1) local!selection
for the grid's current selection, and (2) local!selectedEmployees
for the row data of those selections.
To add these local variables, you finally get to switch to expression mode.
a!localVariables()
function, and add two local variables:
local!selection
local!selectedEmployees
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!selection,
! local!selectedEmployees,
{
a!gridField(
label: "Read-only Grid",
labelPosition: "ABOVE",
data: a!queryEntity(
entity: cons!EMPLOYEE_ENTITY,
query: a!query(
selection: a!querySelection(
columns: {
a!queryColumn(
field: "id"
),
a!queryColumn(
field: "firstName"
),
a!queryColumn(
field: "lastName"
),
a!queryColumn(
field: "department"
),
a!queryColumn(
field: "startDate"
)
}
),
pagingInfo: fv!pagingInfo
),
fetchTotalCount: true
),
columns: {
a!gridColumn(
label: "First Name",
sortField: "firstName",
value: fv!row.firstName
),
a!gridColumn(
label: "Last Name",
sortField: "lastName",
value: fv!row.lastName
),
a!gridColumn(
label: "Department",
sortField: "department",
value: a!richTextDisplayField(
value: {
a!richTextItem(
text: {fv!row.department},
color: if(fv!row.department="Sales", "SECONDARY", null),
style: {
"EMPHASIS"
}
)
}
)
),
a!gridColumn(
label: "Start Date",
sortField: "startDate",
value: fv!row.startDate,
align: "END"
)
},
pagesize: 5,
initialsorts: {
a!sortInfo(
field: "lastName",
ascending: true
)
},
selectable: true,
validations: {}
)
}
! )
Make sure you got that final, close parenthesis on line 78.
Now, switch back to DESIGN MODE.
Select the Read-only Grid to get to the component configuration.
In the expression editor, enter this expression:
1
2
3
4
5
6
7
{
local!selection,
/* This save adds the full rows of data for items selected in the most recent user interaction to local!selectedEmployees. */
a!save(local!selectedEmployees, append(local!selectedEmployees, fv!selectedRows)),
/* This save removes the full rows of data for items deselected in the most recent user interaction to local!selectedEmployees. */
a!save(local!selectedEmployees, difference(local!selectedEmployees, fv!deselectedRows))
}
You can now persist your selection. Try it out by selecting and deselecting rows. The selection index is saved to local!selection
, and the row data for those selections is saved to local!selectedEmployees
; you can't see that yet, but we'll set that up in the next section.
The grid is actually smart enough to use a single selection variable for both the selection index and the row data when you embed a query that returns a primary key, as the query will create a datasubset with the primary key as the identifiers. You can test it out by setting the Selection Value to local!selectedEmployees.id
. If you only pass the data, the grid won't know which field is the primary key, so you'll need to create a second variable for the selection index; we show the two-variable method in this tutorial because it works in both cases.
It's time to configure the second column of our interface to show the employee names of the selected rows. With the components we want already setup, we're going to wrap them in a looping function (a!forEach()
) to reuse them for every employee in local!selectedEmployees
.
Hover over Display Value until the Edit as Expression icon () appears, then click it. You will see the following expression in the editor:
1
2
3
4
5
6
{
a!richTextIcon(
icon: "user-circle"
),
" First Last"
}
Replace that expression with this one:
1
2
3
4
5
6
7
8
9
a!forEach(
items: local!selectedEmployees,
expression: {
a!richTextIcon(
icon: "user-circle"
),
" "&fv!item.firstName &" "&fv!item.lastName&char(10)
}
)
Select one of the rows in the grid to see that name appear on the right.
Changing the color of "Sales" isn't enough; to prevent users from selecting anyone in the Sales department, we're going to tell the grid to disable selection for rows when the department in that row is "Sales."
fv!row.department="Sales"
Now employees in Sales can't even be selected from the grid. Try it out for yourself.
Now that you've had a good look at your grid, you realize not everyone will be interested in seeing those employees in Sales who aren't eligible for the raffle. So, we're going to add an option to hide those rows with a checkbox. For this, we're going to use the method described in the Configure a Boolean Checkbox pattern.
Before we create the checkbox, let's first create a local variable to store the checkbox value, and set a default value on load.
Insert another local variable (local!showIneligible: true
) on line 4.
1
2
3
4
5
6
7
8
9
10
a!localVariables(
local!selection,
local!selectedEmployees,
`local!showIneligible: true,`
{
a!checkboxField(
label: "Checkboxes",
labelPosition: "COLLAPSED",
choiceLabels: {"Show ineligible employees"},
choiceValues: {true},
Now that we have the local variable, we're ready to setup the checkbox to have only one option, and for that option to toggle true
and null
in the variable to act as a switch for the filter we will create in the next section.
Drag a Checkboxes component from the palette onto the canvas, just above the grid.
Replace the text for the first item with: Show ineligible employees
1
) with: true
Click OK.
if(local!showIneligible, true, null)
Enter this expression:
1
2
3
4
5
6
7
8
a!save(
local!showIneligible,
if(
isnull(save!value),
false,
true
)
)
Now the checkbox is all setup; let's connect a query filter to it.
We're going to add a simple filter to the query to exclude Sales that will only run when the checkbox variable (local!showIneligible
) is false
.
Sales
.not(local!showIneligible)
Your filter should look like this:
Now you can toggle the checkbox on and off to see those rows with "Sales" in them disappear!
Now that it's all working, let's wrap up:
Employee Directory
.Selected Employees
.And that's it!
We know that was pretty easy, but you should feel proud anyway.
What you do next, is up to you.
Learn more about the Read-Only Grid, and find more patterns and examples here.