Recently, a client approached us with a requirement to update content fragment elements data, Assets metadata, and Folder metadata via an Azure-based API. Our initial solution was to implement a JMX script, which could be started by an admin user group with valid parameters. However, this was a rather limiting solution, as normal AEM authors did not have the necessary permissions to perform these operations.
To solve this problem, the client requested us to provide a custom action button in the AEM Assets Menu. This button would enable AEM authors who have permission to modify the AEM Asset metadata to update the AEM assets by triggering the action button for the selected AEM assets. This custom implementation proved to be very helpful to the client, as they could easily access the AEM Assets Menu and trigger the custom action button.
This blog post will discuss how we implemented this custom action button.
Overlay the Node
- Go to AEM’s CRXDE.
- Jump on /libs/dam/gui/content/assets/jcr:content/actions/selection Path
- Right-click on the Selection node and select the Overlay Node option from the pop-up menu.
- Make sure the Overlay location is under /apps/ folder, and the Match Node Types option should be checked.
- This will look as follows.
Add Custom Action Bar Node
To add a custom action button in the Action menu, we need to create one action bar child node below Selection Now. Let’s do that!
- Create a node named custom-action-btn (you can put any name here) and set the following properties on a node.
XML Format
<custom-action-btn granite:class="foundation-collection-action suraj-custom-action-btn" jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/collection/action" activeSelectionCount="single" icon="refresh" text="Refresh Asset Data" title="Refresh Asset Data" variant="actionBar"> <granite:rendercondition jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/renderconditions/and"> <haspermission jcr:primaryType="nt:unstructured" sling:resourceType="dam/gui/coral/components/commons/renderconditions/haspermissions" path="${requestPathInfo.suffix}" privileges="[modify_property]"/> </granite:rendercondition> </custom-action-btn>
- You can also set granite:rendercondition if you want to handle specific scenarios in order to display this custom action button (example Provided in the above code to display this action button to the AEM user who has modify_property permission)
we are done with the overlay part. The next step is to write a custom action using Ajax call, or else you can also use custom wizards to perform any operation using this action button. But here, I will be handling custom actions using Ajax calls.
To show the action button for specific conditions, let’s consider action button should only display when the AEM author selects the Content Fragment; in that case, we need to write a custom JS code to enable and disable the visibility for the action button.
Create a JS file inside the client library folder by specifying clientlib categories as dam.gui.actions.coral
- Asset-editor-action-btn-visibility.js
(function(document, $) { "use strict"; //initially hide the refresh asset button $(document).trigger("foundation-contentloaded"); $(".suraj-custom-action-btn").addClass("foundation-collection-action-hidden"); // hide/show refresh asset btn when author select CF asset. $(document).on("foundation-selections-change", ".foundation-collection", function(e) { let view = $("body").data("shell-collectionpage-view-layoutid"); if (view === "list" || view === "column") { let selectedItem = $(this).find(".foundation-collection-item.foundation-selections-item"); let itemType = $(selectedItem).data("editorkey"); if (itemType?.trim() === "contentfragment") { var contentFragmentPath = $(selectedItem).data("foundation-collection-item-id"); if(contentFragmentPath.includes("/sample-cf/")){ $(".suraj-custom-action-btn").removeClass("foundation-collection-action-hidden"); } } } else if (view === "card") { let selectedItem = $(this).find(".foundation-collection-item.foundation-selections-item"); let itemType = $(selectedItem).find("[data-editorkey]").data("editorkey"); if (itemType?.trim() === "contentfragment") { var contentFragmentPath = $(selectedItem).data("foundation-collection-item-id"); if(contentFragmentPath.includes("/projects/")){ $(".suraj-custom-action-btn").removeClass("foundation-collection-action-hidden"); } } } }); })(document, Granite.$);
Now create another JS file to handle the custom action when the Author triggers the custom action button.
- Trigger-custom-action-btn.js
(function(document, $) { "use strict"; // On click of Refresh Asset button update the selected CF $(document).on("click", ".foundation-collection-action.suraj-custom-action-btn", function(e) { let selectedElements = $(".foundation-collection-item.foundation-selections-item.is-selected"); var items = []; $(selectedElements).each(function(e) { let data = $(this).data("foundation-collection-item-id"); items.push(data); }); let message = "<h3>Updating data for following Selected CF</h3>" + items.toString().replaceAll(",", "<br>"); //Show wait ticker untill response is received from ajax call. const $UI = $(window).adaptTo("foundation-ui"); var $waitTicker = $UI.waitTicker("Updating Asset", message); // Ajax to update selected CF. $.ajax({ type: 'POST', url: '<Enter servlet path or API Path which will return the JSON output>', data: JSON.stringify(items), contentType: "application/json", dataType: "json", success: function(response) { if (response.status === 200) { // do some additional stuff with response as per requirement. $UI.alert("Success", response.message, "success"); $waitTicker.clear(); } else { $UI.alert("Error", "Failed to update selected Content Fragments", "error"); $waitTicker.clear(); } }, error: function() { $UI.alert("Error", "Failed to update selected Content Fragments", "error"); $waitTicker.clear(); } }); }); })(document, Granite.$);
Include both the JS files in the js.txt file of your client library folder.
We are done with the implementation part. Now go to the Asset folder and select any Content Fragment. The action button named Refresh Asset Data item appears in the top action bar asset Menu Navigation. Click the Refresh Asset data button to see the following pop-up window for trigger action!
Checkout my Adobe AEM-related perficient blogs here…
The guide on AEM customization for adding a custom action button to the AEM Assets Action Bar Menu is informative. It outlines the steps concisely and provides a clear path for users to follow. However, enhancing the tutorial with visual aids, such as screenshots or code snippets, could improve its effectiveness by offering a more visual reference for users. Overall, it’s a valuable resource for those looking to customize their AEM experience.