Grid with Selection Pattern

This pattern provides useful save behavior and is an example of good UX design for a grid that allows users to select items and easily view their selections when there are multiple pages of data. This page explains how you can use the grid with selection pattern in your interface, and walks you through the design structure of the pattern in detail.

grid_with_selection_pattern_orig.png

Design Structure

The main components in this pattern are a rich text header, grid field, and column layout. The image below displays how the pattern looks on a blank interface with callouts of the main components. You can examine the entire expression or jump down to the subsections below with referenced line numbers to see a detailed breakdown of the main components.

grid_with_selection_pattern.png

Pattern Expression

When you drag and drop the grid with selection pattern onto your interface, 102 lines of expressions will be added to the section where you dragged it.

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
{
  a!localVariables(
    /* This variable is used to persist the checkbox on selected items by holding the identifiers of the selected rows. */
    local!selection,
    /* This variable would be used to pass the full rows of data on the selected items out of this interface, such as to a process model. */
    local!selectedEmployees,
    {
      a!richTextDisplayField(
        label: "",
        labelPosition: "COLLAPSED",
        value: {
          a!richTextHeader(
            text: "Performance Review Portal"
          )
        }
      ),
      a!columnsLayout(
        columns:{
          a!columnLayout(
            contents:{
              a!gridField(
                label: "Employee Directory",
                /* Replace the dummy data with a query, rule, or function that returns a datasubset and uses fv!pagingInfo as the paging configuration. */
                data: todatasubset(
                  {
                    {id: 11, name: "Elizabeth Ward",  dept: "Engineering",     role: "Senior Engineer",       team: "Front-End Components",     pto: 15, startDate: today()-500},
                    {id: 22, name: "Michael Johnson", dept: "Finance",         role: "Payroll Manager",       team: "Accounts Payable",         pto: 2,  startDate: today()-100},
                    {id: 33, name: "John Smith",      dept: "Engineering",     role: "Quality Engineer",      team: "User Acceptance Testing",  pto: 5,  startDate: today()-1000},
                    {id: 44, name: "Diana Hellstrom", dept: "Engineering",     role: "UX Designer",           team: "User Experience",          pto: 49, startDate: today()-1200},
                    {id: 55, name: "Francois Morin",  dept: "Sales",           role: "Account Executive",     team: "Commercial North America", pto: 15, startDate: today()-700},
                    {id: 66, name: "Maya Kapoor",     dept: "Sales",           role: "Regional Director",     team: "Front-End Components",     pto: 15, startDate: today()-1400},
                    {id: 77, name: "Anthony Wu",      dept: "Human Resources", role: "Benefits Coordinator",  team: "Accounts Payable",         pto: 2,  startDate: today()-300}
                  },
                  fv!pagingInfo
                ),
                columns: {
                  a!gridColumn(
                    label: "Name",
                    sortField: "name",
                    value: fv!row.name
                  ),
                  a!gridColumn(
                    label: "Department",
                    sortField: "dept",
                    value: fv!row.dept
                  ),
                  a!gridColumn(
                    label: "Start Date",
                    sortField: "startDate",
                    value: fv!row.startDate,
                    align: "END"
                  )
                },
                pageSize: 3,
                selectable: true,
                selectionValue: local!selection,
                selectionSaveInto: {
                  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))
                }
              )
            }
          ),
          a!columnLayout(
            contents:{
              a!richTextDisplayField(
                label: "Selected Employees",
                value: {
                  if(
                    or(isnull(local!selectedEmployees), length(local!selectedEmployees) = 0),
                    a!richTextItem(
                      text: "None",
                      style: "EMPHASIS"
                    ),
                    a!forEach(
                      local!selectedEmployees,
                      {
                        a!richTextIcon(
                          icon: "USER-CIRCLE",
                          color: "ACCENT"
                        ),
                        "  ",
                        a!richTextItem(
                          text: fv!item.name
                        ),
                        char(10)
                      }
                    )
                  )
                }
              )
            },
            width: "NARROW"
          )
        }
      )
    }
  )
}

[Line 1-54] Define Local Variables and Grid Data

We put the data directly into the grid, and we let the grid handle the paging information with fv!pagingInfo.

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
{
  a!localVariables(
    /* This variable is used to persist the checkbox on selected items by holding the identifiers of the selected rows. */
    local!selection,
    /* This variable would be used to pass the full rows of data on the selected items out of this interface, such as to a process model. */
    local!selectedEmployees,
    {
      a!richTextDisplayField(
        label: "",
        labelPosition: "COLLAPSED",
        value: {
          a!richTextHeader(
            text: "Performance Review Portal"
          )
        }
      ),
      a!columnsLayout(
        columns:{
          a!columnLayout(
            contents:{
              a!gridField(
                label: "Employee Directory",
                /* Replace the dummy data with a query, rule, or function that returns a datasubset and uses fv!pagingInfo as the paging configuration. */
                data: todatasubset(
                  {
                    {id: 11, name: "Elizabeth Ward",  dept: "Engineering",     role: "Senior Engineer",       team: "Front-End Components",     pto: 15, startDate: today()-500},
                    {id: 22, name: "Michael Johnson", dept: "Finance",         role: "Payroll Manager",       team: "Accounts Payable",         pto: 2,  startDate: today()-100},
                    {id: 33, name: "John Smith",      dept: "Engineering",     role: "Quality Engineer",      team: "User Acceptance Testing",  pto: 5,  startDate: today()-1000},
                    {id: 44, name: "Diana Hellstrom", dept: "Engineering",     role: "UX Designer",           team: "User Experience",          pto: 49, startDate: today()-1200},
                    {id: 55, name: "Francois Morin",  dept: "Sales",           role: "Account Executive",     team: "Commercial North America", pto: 15, startDate: today()-700},
                    {id: 66, name: "Maya Kapoor",     dept: "Sales",           role: "Regional Director",     team: "Front-End Components",     pto: 15, startDate: today()-1400},
                    {id: 77, name: "Anthony Wu",      dept: "Human Resources", role: "Benefits Coordinator",  team: "Accounts Payable",         pto: 2,  startDate: today()-300}
                  },
                  `fv!pagingInfo`
                ),
                columns: {
                  a!gridColumn(
                    label: "Name",
                    sortField: "name",
                    value: fv!row.name
                  ),
                  a!gridColumn(
                    label: "Department",
                    sortField: "dept",
                    value: fv!row.dept
                  ),
                  a!gridColumn(
                    label: "Start Date",
                    sortField: "startDate",
                    value: fv!row.startDate,
                    align: "END"
                  )
                },
                `pageSize: 3`,

[Line 55-66] Selection Options

Selection for grids is enabled with the selectable parameter. While local!selection contains the current grid selection for proper display, local!selectedEmployees contains the row information from those selections. This is accomplished from the selectionSaveInto parameter with its function variables (fv!selectedRows and fv!deselectedRows) that contain the row information from each user interaction; appending the selected rows, and removing the deselected rows from local!selectedEmployees so that it contains all the information necessary for the detail view in the second column.

55
56
57
58
59
60
61
62
63
64
65
66
                selectable: true,
                selectionValue: local!selection,
                selectionSaveInto: {
                  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, remove(local!selectedEmployees, wherecontains(`fv!deselectedRows`, local!selectedEmployees)))
                }
              )
            }
          ),

[Line 67-102] Rich Text Header for Detail View

The next column contains the detail view for the grid selection, using a rich text component.

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
          a!columnLayout(
            contents:{
              a!richTextDisplayField(
                label: "Selected Employees",
                value: {
                  if(
                    or(isnull(local!selectedEmployees), length(local!selectedEmployees) = 0),
                    a!richTextItem(
                      text: "None",
                      style: "EMPHASIS"
                    ),
                    a!forEach(
                      local!selectedEmployees,
                      {
                        a!richTextIcon(
                          icon: "USER-CIRCLE",
                          color: "ACCENT"
                        ),
                        "  ",
                        a!richTextItem(
                          text: fv!item.name
                        ),
                        char(10)
                      }
                    )
                  )
                }
              )
            },
            width: "NARROW"
          )
        }
      )
    }
  )
}
FEEDBACK