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
		]
	}
}

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.

Contact Customer FX for your CRM project
We let our expertise speak for itself - let us know how our all-star team can help on your CRM project
About the Author
Ryan Farley
Ryan Farleyhttps://customerfx.com/article/author/ryanfarley/
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.

14 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’

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

  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.

  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

  5. I wonder how can we check the current number of records in the list form in the front-end code.

    Also I wonder how can we access the data in individual lines, but for now I just need to know at least if the list currently is empty or not. This will be used as one of the conditions to decide whether we allow saving the record or not.

  6. Hi Rayan,

    Can we show and hide these buttons based on the specific value in a column in that list? For example, we have a status column. If the status is in draft stage, we should show the delete option; otherwise, we should hide it. This should affect every single row in the freedom UI detail.

    Thank you.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

AI Readiness Checklist for CRM Teams: Is Your CRM System Ready for AI?

Before using AI in Creatio, make sure your CRM data, users, processes, and automation foundation are ready. Use this practical AI readiness checklist for CRM teams.

Build Your Creatio AI Skills with the 2026 AI Summer Program

Join Creatio’s free 2026 AI Summer Program to learn how to identify, build, deploy, and manage AI agents.

Creatio 10x Is Coming: Join the Webinar to Explore the Future of AI-Native CRM

Learn what's new in Creatio 10x and how AI-native CRM, agentic AI, and no-code automation are shaping the future of customer relationship management. Join the upcoming webinar and discover what's next.

Creatio Unlimited Pricing Explained: AI Packages, Costs, Pros & Cons

Learn what Creatio’s new Unlimited pricing model includes, what it doesn’t include, how AI Action packages work, and the pros and cons for businesses evaluating Creatio.

Using the AI Prompt to Create Dynamic Folders in Creatio

Using Creatio's AI prompt to create the filter for a dynamic folder works best if you specifically ask for that, and if you are as clear and direct as possible about the filtering, conditions.

Related Articles

AI Readiness Checklist for CRM Teams: Is Your CRM System Ready for AI?

Before using AI in Creatio, make sure your CRM data, users, processes, and automation foundation are ready. Use this practical AI readiness checklist for CRM teams.

Build Your Creatio AI Skills with the 2026 AI Summer Program

Join Creatio’s free 2026 AI Summer Program to learn how to identify, build, deploy, and manage AI agents.

Creatio 10x Is Coming: Join the Webinar to Explore the Future of AI-Native CRM

Learn what's new in Creatio 10x and how AI-native CRM, agentic AI, and no-code automation are shaping the future of customer relationship management. Join the upcoming webinar and discover what's next.

Creatio Unlimited Pricing Explained: AI Packages, Costs, Pros & Cons

Learn what Creatio’s new Unlimited pricing model includes, what it doesn’t include, how AI Action packages work, and the pros and cons for businesses evaluating Creatio.

Related Videos