Limit the Number of Rows in a Grid That Can Be Selected

Interface patterns give you an opportunity to explore different interface designs. Be sure to check out How to Adapt a Pattern for Your Application.

Goal

Limit the number of rows that can be selected to an arbitrary number.

This expression uses direct references to the Employee record type, created in the Records Tutorial. If you've completed that tutorial in your environment, you can change the existing record-type references in this pattern to point to your Employee record type instead.

This is a more elaborate version of the Limit Grid Selection to One Row pattern.

limit-number-of-rows-selected.png

This scenario demonstrates:

  • How to configure grid selection in a Read-Only Grid.
  • How to limit selection to an arbitrary number.

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
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
103
104
105
106
107
108
109
110
111
112
113
114
115
a!localVariables(
  local!selection,
  local!selectedRows,
  /* This is the maximum number of rows you can select from the grid. Selections that exceed
     this value are dropped from local!selectedRows. */
  local!selectionLimit: 2,
  /* This stores the last dropped row that exceeded the selection limit. */
  local!errorDrop,
  {
    a!columnsLayout(
      columns: {
        a!columnLayout(
          contents: {
            a!gridField(
              label: "Employees",
              labelPosition: "ABOVE",
              instructions: "Select up to " & local!selectionLimit & " employees.",
              data: recordType!Employee,
              columns: {
                a!gridColumn(
                  label: "ID",
                  sortField: "id",
                  value: fv!row[recordType!Employee.fields.id],
                  width: "ICON"
                ),
                a!gridColumn(
                  label: "First Name",
                  sortField: "firstName",
                  value: fv!row[recordType!Employee.fields.firstName]
                ),
                a!gridColumn(
                  label: "Last Name",
                  sortField: "lastName",
                  value: fv!row[recordType!Employee.fields.lastName]
                ),
                a!gridColumn(
                  label: "Phone Number",
                  sortField: "phoneNumber",
                  value: fv!row[recordType!Employee.fields.phoneNumber]
                )
              },
              pagesize: 10,
              selectable: true,
              selectionstyle: "ROW_HIGHLIGHT",
              selectionvalue: local!selection,
              selectionsaveinto: {
                local!selection,
                a!save(local!selectedRows, append(local!selectedRows, fv!selectedRows)),
                a!save(local!selectedRows, difference(local!selectedRows, fv!deselectedRows)),
                /* If the length of the selected rows is greater than the limit, this saves the excess
                   selection in local!errorDrop so we can tell the user which row was dropped. */
                if(length(local!selectedRows) > local!selectionLimit, 
                  a!save(local!errorDrop, fv!selectedRows),
                  a!save(local!errorDrop, null)
                ),
                /* We use the rdrop() function to remove the most recent selections, so only the
                   first-selected rows, up to the limit, remain. If you want the reverse behavior, 
                   dropping the oldest selections instead, replace rdrop() with ldrop().

                   The max() function is used as a simple way to handle negative numbers for when 
                   the selection length is less than the limit. */
                a!save(local!selectedRows, rdrop(local!selectedRows, max(0, length(local!selectedRows)-local!selectionLimit))),
                a!save(local!selection, rdrop(local!selection, max(0, length(local!selection)-local!selectionLimit)))
              },
              validations: a!validationMessage(
                message: "The total cannot be greater than $1,000",
                validateAfter: "REFRESH",
                showWhen: true
              )
            )
          },
          width: "WIDE"
        ),
        a!columnLayout(
          contents: {
            a!sectionLayout(
              label: "Selected Employees",
              contents: {
                a!forEach(
                  items: local!selectedRows,
                  expression: a!textField(
                    label: fv!index&". "&fv!item[recordType!Employee.fields.firstName]&" "&fv!item[recordType!Employee.fields.lastName],
                    value: "    "&fv!item[recordType!Employee.fields.phoneNumber],
                    readOnly: true
                  )
                )
              }
            ),
            a!richTextDisplayField(
              label: "Rich Text",
              labelPosition: "COLLAPSED",
              value: {
                a!richTextItem(
                  text: {
                    if(
                      not(isnull(local!errorDrop)),
                      "Can't add "
                      &local!errorDrop[recordType!Employee.fields.firstName] &" "& local!errorDrop[recordType!Employee.fields.lastName] &"."
                      &char(10)&"Maximum selections: "&local!selectionLimit,
                      ""
                    )
                  },
                  color: "NEGATIVE",
                  style: {
                    "STRONG"
                  }
                )
              }
            )
          }
        )
      }
    )
  }
)

Test it out

  1. Select multiple rows and note that only the last selection persists.
Open in Github
FEEDBACK