Display live contact list statistics
This functionality is available for Creatio 8.3.2 and later.
To implement the example:
- Set up the page UI. Read more >>>
- Set up the displaying of live contact list statistics. Read more >>>
Display live statistics for the Contacts section.
- Display the number of contacts currently loaded and shown in the list in the Displayed contacts label.
- Display a list of contact list updates in the Contact list activity log field.
Both elements must be updated automatically without a manual page refresh. They are updated when you create or delete a contact, refresh the contact list, or scroll the page to load additional records.
1. Set up the page UI
-
Click
in the top right → Application management → Application Hub → Customer 360 → Contacts list page. -
Add a label.
For this example, add a label that contains the number of currently loaded contacts.
To do this:
-
Add a label to the canvas.
-
Click
and fill out the label properties.Element
Property
Property value
Label that contains the number of currently loaded contacts
Text
Displayed contacts
Style
Body
Element code
UsrDisplayedContacts
-
-
Add a field.
For this example, add a field that contains a list of contact list changes, such as added or removed contacts.
To do this:
-
Add a "Text" type field to the canvas.
-
Click
and fill out the field properties.Element
Property
Property value
Field that contains a list of contact list changes
Title
Contact list activity log
Code
UsrContactListActivityLog
Format
Text (500 characters)
Multiline text
Select the checkbox
Element code
UsrContactListActivityLog
-
-
Save the changes.
2. Set up the displaying of live contact list statistics
Configure the business logic in the Client Module Designer. For this example, display live contact list statistics.
-
Click
→ Source code to open the source code of the Freedom UI page. -
Add an attribute.
- Go to the
viewModelConfigDiffschema section →valuesconfiguration object. - Add a
DisplayedContactsattribute that stores data about number of currently loaded contacts. - Add a
ContactListActivityLogattribute that stores data about contact list changes.
viewModelConfigDiff schema sectionviewModelConfigDiff: /**SCHEMA_VIEW_MODEL_CONFIG_DIFF*/[
...,
{
"operation": "merge",
"path": [
"attributes"
],
"values": {
...,
/* The attribute that stores data about number of currently loaded
contacts. */
"DisplayedContacts": {},
/* The attribute that stores data about contact list changes. */
"ContactListActivityLog": {}
}
}
]/**SCHEMA_VIEW_MODEL_CONFIG_DIFF*/, - Go to the
-
Bind an attribute to the page elements.
- Go to the
viewConfigDiffschema section →UsrDisplayedContactselement. - Bind the
$DisplayedContactsattribute to thecaptionproperty. - Go to the
UsrContactListActivityLogelement. - Bind the
$ContactListActivityLogattribute to thecontrolproperty.
viewConfigDiff schema sectionviewConfigDiff: /**SCHEMA_VIEW_CONFIG_DIFF*/[
...,
/* Label that contains the number of currently loaded contacts. */
{
"operation": "insert",
"name": "UsrDisplayedContacts",
"values": {
...,
/* The property that handles the text contained in the element.
Bound to the "DisplayedContacts" attribute. */
"caption": "$DisplayedContacts",
...,
},
...
},
/* Field that contains a list of contact list changes. */
{
"operation": "insert",
"name": "UsrContactListActivityLog",
"values": {
...,
/* The property that binds the control contained in the element.
Bound to the "ContactListActivityLog" attribute. */
"control": "$ContactListActivityLog",
...,
},
...
},
]/**SCHEMA_VIEW_CONFIG_DIFF*/, - Go to the
-
Implement the base request handler.
- Go to the
handlersschema section. - Add a custom implementation of the
crt.HandleViewModelInitRequestbase request handler.
handlers schema sectionhandlers: /**SCHEMA_HANDLERS*/[
{
request: "crt.HandleViewModelInitRequest",
handler: async (request, next) => {
/* Retrieve the contact collection. */
const collection = await request.$context.Items;
/* Initialize UI values so controls render immediately. */
request.$context.DisplayedContacts =
`Displayed contacts: ${collection?.length ?? 0}`;
request.$context.ContactListActivityLog =
(await request.$context.ContactListActivityLog) || "";
/* Object to convert collection change action codes to readable
action names. */
const actionsMap = {
add: "Added",
remove: "Removed",
move: "Moved",
reload: "Refreshed contact list"
};
/* Detect bulk "add" events (10+ items) caused by list virtualization
(scrolling) or initial page load. */
const isBulkAdd = (changes) =>
changes.action === "add" &&
(changes.affectedElements?.length ?? 0) >= 10;
/* Ignore "move" events because they usually represent internal
list reordering. */
const isNoiseMove = (changes) => changes.action === "move";
/* Update the current number of displayed contacts. */
const updateTotal = (changes) => {
request.$context.DisplayedContacts =
`Displayed contacts: ${changes.collection.length}`;
};
/* Update the contact list activity log. */
const updateLog = async (changes) => {
const log = (await request.$context.ContactListActivityLog) || "";
const divider = log ? "\n" : "";
/* Treat bulk add (scroll/page load) as a list refresh event. */
if (isBulkAdd(changes)) {
request.$context.ContactListActivityLog =
`${log}${divider}${actionsMap.reload}`;
return;
}
if (isNoiseMove(changes)) {
return;
}
/* Log reload as a list-level event (no count). */
if (changes.action === "reload") {
request.$context.ContactListActivityLog =
`${log}${divider}${actionsMap.reload}`;
return;
}
const actionName = actionsMap[changes.action] ?? changes.action;
const count = changes.affectedElements?.length ?? 0;
const item = count === 1 ? "contact" : "contacts";
request.$context.ContactListActivityLog =
`${log}${divider}${actionName} ${count} ${item}`;
};
collection.registerOnCollectionChangeCallback(updateTotal);
collection.registerOnCollectionChangeCallback(updateLog);
return next?.handle(request);
}
}
]/**SCHEMA_HANDLERS*/, - Go to the
-
Save the changes.
View the result
-
Open the Contacts section.
-
Perform several arbitrary actions that modify the contact list. For example:
- Create a contact. For example, "Alice Best."
- Delete a contact. For example, "Alice Best."
- Refresh the contact list
- Scroll the page
As a result, Creatio will update the Displayed contacts and Contact list activity log values automatically when you create or delete a contact, refresh the contact list, or scroll the page without requiring a manual refresh.
Source code
/* Declare the AMD module. */
define("Contacts_ListPage",
/**SCHEMA_DEPS*/[]/**SCHEMA_DEPS*/,
function/**SCHEMA_ARGS*/()/**SCHEMA_ARGS*/ {
return {
viewConfigDiff: /**SCHEMA_VIEW_CONFIG_DIFF*/[
{
"operation": "insert",
"name": "FlexContainer_r7cat2b",
"values": {
"type": "crt.FlexContainer",
"direction": "column",
"items": [],
"fitContent": true
},
"parentName": "SectionContentWrapper",
"propertyName": "items",
"index": 1
},
/* Label that contains the number of currently loaded contacts. */
{
"operation": "insert",
"name": "UsrDisplayedContacts",
"values": {
"type": "crt.Label",
/* The property that handles the text contained in the element.
Bound to the "DisplayedContacts" attribute. */
"caption": "$DisplayedContacts",
"labelType": "body",
"labelThickness": "default",
"labelEllipsis": false,
"labelColor": "auto",
"labelBackgroundColor": "transparent",
"labelTextAlign": "start",
"headingLevel": "label",
"visible": true
},
"parentName": "FlexContainer_r7cat2b",
"propertyName": "items",
"index": 0
},
/* Field that contains a list of contact list changes. */
{
"operation": "insert",
"name": "UsrContactListActivityLog",
"values": {
"type": "crt.Input",
"label": "#ResourceString(UsrContactListActivityLog_label)#",
/* The property that binds the control contained in the element.
Bound to the "ContactListActivityLog" attribute. */
"control": "$ContactListActivityLog",
"placeholder": "",
"tooltip": "",
"readonly": false,
"multiline": true,
"labelPosition": "auto",
"visible": true
},
"parentName": "FlexContainer_r7cat2b",
"propertyName": "items",
"index": 1
}
]/**SCHEMA_VIEW_CONFIG_DIFF*/,
viewModelConfigDiff: /**SCHEMA_VIEW_MODEL_CONFIG_DIFF*/[
{
"operation": "merge",
"path": [
"attributes"
],
"values": {
/* The attribute that stores data about number of currently loaded
contacts. */
"DisplayedContacts": {},
/* The attribute that stores data about contact list changes. */
"ContactListActivityLog": {}
}
}
]/**SCHEMA_VIEW_MODEL_CONFIG_DIFF*/,
modelConfigDiff: /**SCHEMA_MODEL_CONFIG_DIFF*/[]/**SCHEMA_MODEL_CONFIG_DIFF*/,
handlers: /**SCHEMA_HANDLERS*/[
{
request: "crt.HandleViewModelInitRequest",
handler: async (request, next) => {
/* Retrieve the contact collection. */
const collection = await request.$context.Items;
/* Initialize UI values so controls render immediately. */
request.$context.DisplayedContacts =
`Displayed contacts: ${collection?.length ?? 0}`;
request.$context.ContactListActivityLog =
(await request.$context.ContactListActivityLog) || "";
/* Object to convert collection change action codes to readable
action names. */
const actionsMap = {
add: "Added",
remove: "Removed",
move: "Moved",
reload: "Refreshed contact list"
};
/* Detect bulk "add" events (10+ items) caused by list virtualization
(scrolling) or initial page load. */
const isBulkAdd = (changes) =>
changes.action === "add" &&
(changes.affectedElements?.length ?? 0) >= 10;
/* Ignore "move" events because they usually represent internal
list reordering. */
const isNoiseMove = (changes) => changes.action === "move";
/* Update the current number of displayed contacts. */
const updateTotal = (changes) => {
request.$context.DisplayedContacts =
`Displayed contacts: ${changes.collection.length}`;
};
/* Update the contact list activity log. */
const updateLog = async (changes) => {
const log = (await request.$context.ContactListActivityLog) || "";
const divider = log ? "\n" : "";
/* Treat bulk add (scroll/page load) as a list refresh event. */
if (isBulkAdd(changes)) {
request.$context.ContactListActivityLog =
`${log}${divider}${actionsMap.reload}`;
return;
}
if (isNoiseMove(changes)) {
return;
}
/* Log reload as a list-level event (no count). */
if (changes.action === "reload") {
request.$context.ContactListActivityLog =
`${log}${divider}${actionsMap.reload}`;
return;
}
const actionName = actionsMap[changes.action] ?? changes.action;
const count = changes.affectedElements?.length ?? 0;
const item = count === 1 ? "contact" : "contacts";
request.$context.ContactListActivityLog =
`${log}${divider}${actionName} ${count} ${item}`;
};
collection.registerOnCollectionChangeCallback(updateTotal);
collection.registerOnCollectionChangeCallback(updateLog);
return next?.handle(request);
}
}
]/**SCHEMA_HANDLERS*/,
converters: /**SCHEMA_CONVERTERS*/{}/**SCHEMA_CONVERTERS*/,
validators: /**SCHEMA_VALIDATORS*/{}/**SCHEMA_VALIDATORS*/
};
}
);