Adding Row Action Menu Items to a Creatio Freedom UI List

Something I have really grown to love with Freedom UI lists is the ability to add row actions that can be performed for the selected row in a list. These quick actions make a nice way to allow users to perform quick actions without opening the full record page. Here’s a sample of a list with some row actions, these particular row actions are actions I’ve added on the Cases section list:

Adding actions to a list is pretty simple, but currently can’t be done in the page editor and you must modify the page code to add these. You’ll need to find the crt.DataGrid element in the viewConfigDiff. Then, you’ll need to add a node for rowToolbarItems to the values. Here’s a sample:

viewConfigDiff: /**SCHEMA_VIEW_CONFIG_DIFF*/[
    {
        "operation": "merge",
        "name": "DataTable",
        "values": {
            ...,
            "rowToolbarItems": [{
                "type": "crt.MenuItem",
                "caption": "Do something",
                "icon": "open-button-icon",
                "clicked": {
                    "request": "cfx.SomeCustomHandler",
                    "params": {
                        "itemsAttributeName": "Items",
                        "recordId": "$Items.PDS_Id",
                    }
                }
            }]
        }
        ...
    },
    ...
]/**SCHEMA_VIEW_CONFIG_DIFF*/

This row action will execute a request named “cfx.SomeCustomHandler”, which I’ve added to the handlers on the page. It will also include the current record’s Id value as recordId, so I’ll access that in the request as request.recordId. There’s a few things to note about the params part. You’ll need to find a few things out about the crt.DataGrid element first. For section Lists, the Items collection attribute is named “Items” and the primary Id for the row data has an attribute named “PDS_Id” so the code above will work. For other lists you add to a page, you’ll need to find out what these attributes are named. The grid/list will have elements for the following:

"items": "$GridDetail_fei1jz3",
"primaryColumnName": "GridDetail_fei1jz3DS_Id",

With these names, the rowToolbarItem would look as follows:

viewConfigDiff: /**SCHEMA_VIEW_CONFIG_DIFF*/[
    {
        "operation": "merge",
        "name": "DataTable",
        "values": {
            ...,
            "rowToolbarItems": [{
                "type": "crt.MenuItem",
                "caption": "Do something",
                "icon": "open-button-icon",
                "clicked": {
                    "request": "cfx.SomeCustomHandler",
                    "params": {
                        "itemsAttributeName": "GridDetail_fei1jz3",
                        "recordId": "$GridDetail_fei1jz3.GridDetail_fei1jz3DS_Id",
                    }
                }
            }]
        }
        ...
    },
    ...
]/**SCHEMA_VIEW_CONFIG_DIFF*/

Take note, the “itemsAttributeName” does not have a “$” prefix and the “recordId” does. Additionally, the recordId value is the “items” property and “primaryColumnName” values combined as a single string with a “.” in-between. Also, note, you’re absolutely allowed to pass other column values in the params as well, not just the Id, if needed. Also, once you add a rowToolbarItems array to the grid/list, you’ll lose the out of the box actions for Open, Copy, and Delete. If you still want those, you’ll need to add those back. The are defined as follows – Be sure to change the “items” and “primaryColumnName” values as mentioned above (if this is a Section list it can likely stay the same as below, however for a list on a page those will be different):

// default open action
{
    type: 'crt.MenuItem',
    caption: 'DataGrid.RowToolbar.Open',
    icon: 'edit-row-action',
    disabled: "$Items.PrimaryModelMode | crt.IsEqual : 'create'",
    clicked: {
        request: 'crt.UpdateRecordRequest',
        params: {
            "itemsAttributeName": "Items",
            "recordId": "$Items.PDS_Id",
        },
    },
},
// default copy action
{
    type: 'crt.MenuItem',
    caption: 'DataGrid.RowToolbar.Copy',
    icon: 'copy-row-action',
    disabled: "$Items.PrimaryModelMode | crt.IsEqual : 'create'",
    clicked: {
        request: 'crt.CopyRecordRequest',
        params: {
            "itemsAttributeName": "Items",
            "recordId": "$Items.PDS_Id",
        },
    },
},
// default delete action
{
    type: 'crt.MenuItem',
    caption: 'DataGrid.RowToolbar.Delete',
    icon: 'delete-row-action',
    clicked: {
        request: 'crt.DeleteRecordRequest',
        params: {
            "itemsAttributeName": "Items",
            "recordId": "$Items.PDS_Id",
        }
    },
}

Note, if you’re modifying an out of the box list page (Accounts_ListPage for example), then you won’t see the elements for the list in the page code. This is because they’re defined in the parent list page. However, you can merge in changes by adding something like the following to the viewConfigDiff:

{
	"operation": "merge",
	"name": "DataTable",
	"values": {
		"rowToolbarItems": [
			// add any items here, or leave empty
		]
	}
}

Note, you’ll want to check the parent page to make sure that the list element “name” is correct. For section list pages it’s typically DataTable, however, for lists on pages (such as the Cases list on the Accounts_FormPage, etc) that will not be the case so you’ll need to check what the list name is to use for the merge element above.

Handling the Menu Item Request

Once the menu item is added, we’ll need to be able to handle the request, assuming this is a custom request and not an out of the box action (like the open, copy, delete requests above). For handling the request, we’ll add it to the requests of the page. In the first code sample in this article, where we’re adding the “cfx.SomeCustomHandler” request, we’ve added to the “params” a “recordId” param and populated it with the row’s primary Id value. That will get passed into the request as request.recordId:

{
	request: "cfx.SomeCustomHandler",
	handler: async (request, next) => {
		const id = request.recordId;
		// do something here

		return next?.handle(request);
	}
}

We can pass in other attributes bound in the grid as well. Not just the record Id. However, the column must exist in the data for the list. View how to add other columns to the list‘s data.

Once you start adding these row actions, you’ll realize they can be a big time saver & convenience for users. Plus they’re easy to implement so it’s a big win all around.

Want content like this delivered to your inbox? Sign up for our newsletter!
ABOUT THE AUTHOR

Ryan Farley

Ryan Farley is the Director of Development for Customer FX and creator of slxdeveloper.com. He's been blogging regularly about SalesLogix, now Infor CRM, since 2001 and believes in sharing with the community. His new passion for CRM is Creatio, formerly bpm'online. He loves C#, Javascript, web development, open source, and Linux. He also loves his hobby as an amateur filmmaker.

6 Comments

  1. Hi Ryan. Thank you for this helpful article. But I have a question about ‘details’ in Freedom UI. Did you implement some virtual details in Freedom UI? We need to use some webservice to fetch data and just display it to the user in this ‘virtual detail’

    Reply
    • Hello Alex,

      I’ve started trying to piece together what is needed to accomplish this since it’s something I need to do as well. I’ve not yet gotten far enough to know if it’s possible and how to do it yet. So far, it seems like it could be possible, but not sure yet. If I end up making any progress on this, I’ll post the details here for sure.

      Ryan

  2. I’ve tried to analyze Terrasoft’s component ‘crt.DataGrid’ and there are several types of dataSource – EntityDataSource and WebServiceDataSource. So I think that it is possible, but we need to understand how to declare DataGrid with the second type of dataSource. Looking forward to your implementation. if I find a solution, I will definitely share it as well.

    Reply
  3. Hi Ryan. I think I have a solutuion.
    1. Create an object.
    2. Mark it as virtual.
    3. Create a C# class that implement IEntitySchemaQueryExecutor. It has one method GetEntityCollection. Create some entites in it and return them.
    (There are examples by Terrasoft, you can find them by interface’s name)
    IMPORTANT – they use attributes for those classes and I think attribute’s naming is very important:
    [DefaultBinding(typeof(IEntitySchemaQueryExecutor), Name = “UsrMyObjectQueryExecutor”)]

    UsrMyObjectQueryExecutor – this name.

    4. Currently it works with IEntitySchemaQueryExecutor, but it’s marked as obsolete and we need to use IEntityQueryExecutor.

    Reply
  4. Hi Ryan.

    Is it possible to run a business process by clicking this button in the menu? I’m trying to do it but the process is not running

    Thank you!

    JC

    Reply

Submit a Comment

Your email address will not be published. Required fields are marked *