Interface patterns give you an opportunity to explore different interface designs. To learn how to directly use patterns within your interfaces, see How to Adapt a Pattern for Your Application.
This recipe uses an employee data structure and objects created through the Use the Write to Data Store Entity Smart Service Function on an Interface recipe. Make sure that recipes has been built first in order to see data in this recipe.
Display a chart with aggregate data from a data store entity, specifically the total number of employees for each department. Then add links to the chart slices so that when a user clicks on a department, the chart is replaced by a grid that displays all employees for that department with a link to return to the chart.
This design pattern is not recommended for offline interfaces because reflecting immediate changes in an interface based on user interaction requires a connection to the server.
This scenario demonstrates:
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
load(
/* The piechart and paging grid need different paging info values. */
local!chartPagingInfo: a!pagingInfo(
startIndex: 1,
batchSize: -1,
sort: a!sortInfo(
field: "department",
ascending: true
)
),
local!gridPagingInfo: a!pagingInfo(
startIndex: 1,
batchSize: 20,
sort: a!sortInfo(
field: "title",
ascending: true
)
),
local!selectedDepartment,
with(
local!chartDatasubset: a!queryEntity(
entity: cons!EMPLOYEE_ENTITY,
query: a!query(
/* Aggregates data by department for the chart */
aggregation: a!queryAggregation(
aggregationColumns: {
a!queryAggregationColumn(field: "department", isGrouping: true),
a!queryAggregationColumn(field: "id", aggregationFunction: "COUNT"),
}
),
pagingInfo: local!chartPagingInfo
)
),
local!gridDatasubset: if(
isnull(local!selectedDepartment),
{},
/* Returns a set of employees, filtered by department */
a!queryEntity(
entity: cons!EMPLOYEE_ENTITY,
query: a!query(
selection: a!querySelection(
columns: {
a!queryColumn(field: "firstName"),
a!queryColumn(field: "lastName"),
a!queryColumn(field: "title")
}
),
filter: a!queryFilter(field: "department", operator: "=", value: local!selectedDepartment),
pagingInfo: local!gridPagingInfo
),
fetchTotalCount: true
)
),
a!sectionLayout(
contents:{
a!pieChartField(
series: a!forEach(
items: local!chartDatasubset.data,
expression: a!chartSeries(
label: fv!item.department,
data: fv!item.id,
links: a!dynamicLink(value: fv!item.department, saveInto: local!selectedDepartment)
)
),
showWhen: isnull(local!selectedDepartment)
),
a!linkField(
labelPosition: "COLLAPSED",
links: a!dynamicLink(
label: "Back to Chart",
value: null,
saveInto: {
local!selectedDepartment,
/*
* Reset the startIndex back to the first page when the user
* changes the filter. Otherwise, the grid could error out.
*/
a!save(local!gridPagingInfo.startIndex, 1)
},
showWhen:not( isnull(local!selectedDepartment) )
)
),
a!gridField(
label: local!selectedDepartment & " Employees",
totalCount: local!gridDatasubset.totalCount,
columns: {
a!gridTextColumn(
label: "First Name",
field: "firstName",
data: index(local!gridDatasubset.data, "firstName", {})
),
a!gridTextColumn(
label: "Last Name",
field: "lastName",
data: index(local!gridDatasubset.data, "lastName", {})
),
a!gridTextColumn(
label: "Title",
field: "title",
data: index(local!gridDatasubset.data, "title", {})
)
},
value: local!gridPagingInfo,
saveInto: local!gridPagingInfo,
rowHeader: 1,
showWhen: not( isnull( local!selectedDepartment) )
)
}
)
)
)
local!gridPagingInfo
, ensuring that the user will see the first page for the new filter. This is necessary regardless of what the user has selected, so we ignore the value returned by the component and instead insert our own value.department
field is the department name, so it can be used both for display and as the value of the filter. If using a lookup instead, you would need to use the name as a display but save the id instead.