Skip to main content
Version: 8.3

Display live contact list statistics

Level: intermediate
note

This functionality is available for Creatio 8.3.2 and later.

To implement the example:

  1. Set up the page UI. Read more >>>
  2. Set up the displaying of live contact list statistics. Read more >>>
Example

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

  1. Click btn_system_designer.png in the top right → Application managementApplication HubCustomer 360Contacts list page.

  2. Add a label.

    For this example, add a label that contains the number of currently loaded contacts.

    To do this:

    1. Add a label to the canvas.

    2. Click icn_settings_in_freedom_ui_designer.png 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

  3. 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:

    1. Add a "Text" type field to the canvas.

    2. Click icn_settings_in_freedom_ui_designer.png 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

  4. 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.

  1. Click btn_actions_in_freedom_ui_designer.pngSource code to open the source code of the Freedom UI page.

  2. Add an attribute.

    1. Go to the viewModelConfigDiff schema section → values configuration object.
    2. Add a DisplayedContacts attribute that stores data about number of currently loaded contacts.
    3. Add a ContactListActivityLog attribute that stores data about contact list changes.
    viewModelConfigDiff schema section
    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*/,
  3. Bind an attribute to the page elements.

    1. Go to the viewConfigDiff schema section → UsrDisplayedContacts element.
    2. Bind the $DisplayedContacts attribute to the caption property.
    3. Go to the UsrContactListActivityLog element.
    4. Bind the $ContactListActivityLog attribute to the control property.
    viewConfigDiff schema section
    viewConfigDiff: /**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*/,
  4. Implement the base request handler.

    1. Go to the handlers schema section.
    2. Add a custom implementation of the crt.HandleViewModelInitRequest base request handler.
    handlers schema section
    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*/,
  5. Save the changes.

View the result

  1. Open the Contacts section.

  2. 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

Contacts_ListPage
/* 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*/
};
}
);

Resources

Package with example implementation