Introduction
In this post, we’ll build upon concepts from my previous post on Dynamic Routes and Views, where we explored how to create custom sections in Umbraco 14. Specifically, we’ll cover adding actions to trees using the Sidebar Context Menu.
Using Entity Actions
For this we can use the built-in Entity Actions. This feature automatically renders buttons for various actions directly within the sidebar context menu, providing a list of all possible actions relevant to the context.
Registering Actions
To register actions, you’ll need to create manifests of type ManifestEntityAction
. When defining these, you must specify the forEntityTypes
property, which determines which actions are available for each item type.
You can also define an api
property, which specifies the logic that runs when the action is triggered.
manifest.ts:
const folderEntityActionManifest: Array<ManifestEntityAction> = [
{
type: 'entityAction',
alias: 'deleteFolder',
name: 'Delete Folder',
kind: 'default',
api: () => import('./menu-actions/folder/delete-folder-action.api.ts'),
forEntityTypes: [FORMX_ENTITY_FOLDER_ALIAS],
meta: {
icon: 'icon-trash',
label: 'Delete'
},
}
]
Rendering Actions
Actions can be rendered by adding a umb-entity-actions-bundle
element in the action slot of a uui-menu-item
. The entityType
needs to match the one defined in the manifest, and the unique
property represents the unique identifier of the item.
menu-items.ts:
<uui-menu-item>
<umb-entity-actions-bundle
slot="actions"
.entityType=${element.type === 0 ? FORMX_ENTITY_FORM_ALIAS : FORMX_ENTITY_FOLDER_ALIAS}
.unique=${element.id}>
</umb-entity-actions-bundle>
</uui-menu-item>
Action Logic
The functionality of an action is implemented in its corresponding api
class, where you override the execute
method. You can access the unique
property of the selected menu item through this.args.unique
.
On the end of the action logic we can dispatch an event to notify other components using actionEventContext.dispatchEvent(event)
. We can use this later to handle the output of the action.
In this case we can dispatch an UmbRequestReloadStructureForEntityEvent
with entityType “FORMX”, because it doesn’t matter if the deleted item is a form or folder, the whole tree should be updated.
delete-folder-action.api.ts:
export class DeleteFolder extends UmbEntityActionBase<ManifestEntityActionDefaultKind> {
override async execute() {
// Use ModalManager to show a delete confirmation dialog
console.log('Delete folder with id:', this.args.unique);
const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
if(this.args.unique == null)
throw new Error('Unique is required to delete folder');
let id = parseInt(this.args.unique);
const modal = modalManager.open(this, FORMX_DELETE_FOLDER_MODAL, {
data: {
id: id
},
});
modal.onSubmit().then((data) => {
console.log(`Response from modal: ${data}`);
this.getContext(UMB_ACTION_EVENT_CONTEXT)
.then((actionEventContext) => {
const event = new UmbRequestReloadStructureForEntityEvent({
unique: this.args.unique,
entityType: "FORMX",
});
//Dispatch an event
actionEventContext.dispatchEvent(event);
})
})
.catch(() => {
});
}
}
export default DeleteFolder ;
Handling the Action Result
After the action is completed and the sidebar context menu is closed, the tree will not automatically refresh. However, we can listen for events being dispatched. So in this case we will listen for aUmbRequestReloadStructureForEntityEvent
with entityType “FORMX”.
When the event is dispatched, fetch the tree items again and rerender the structure. Using the ?showChildren
attribute, you can maintain the open state of tree items after the refresh.
constructor() {
super();
this.fetchTree(); // Start fetching on component load
this.consumeContext(UMB_ACTION_EVENT_CONTEXT, (instance) => {
this.#actionEventContext = instance;
this.#actionEventContext?.removeEventListener(
UmbRequestReloadStructureForEntityEvent.TYPE,
this.#onReloadStructureRequest as unknown as EventListener,
);
this.#actionEventContext.addEventListener(
UmbRequestReloadStructureForEntityEvent.TYPE,
this.#onReloadStructureRequest as unknown as EventListener,
);
});
}
#onReloadStructureRequest = async (event: UmbRequestReloadStructureForEntityEvent) => {
if(event.getEntityType() == "FORMX"){
//Handle rerender tree
this.fetchTree();
}
}
Next, I added an "Add" action, which will result in the following:
Top comments (0)