There is a common case when we have to extend the AEM component dialog with custom JS code for some cases: field custom validation, to load external data, update field value on any condition, and so on.
Everything is going well until we have a few components or JS logic is not greater than the “hello world” component. But when the project grows alongside with components number we will face dependency hell.
In the scope of components dialogs, we have to keep in mind that every custom include of “extraClientlibs” will live on the page until page reload therefore JS functions could easily break logic in other dialogs during the page editing.
The below steps will help you to avoid common mistakes during implementation:
- DO not include every custom JS client library into the cq.authoring.dialog category:
categories="[cq.authoring.dialog]"
This ClientLibs category has to be used ONLY for utility methods that could be used across all dialogs and wouldn’t break anything.
- Every component dialog with custom JS code have to be placed in a separate category, easy to use package or folder path as a category name, this prevents category name overlap:
categories="[project-a.components.product.wizzard.authoring]"
- Make a rule to put validation that we are working with the required dialog at the JS beginning, if not – bypass the execution:
(function (document, $) { "use strict"; const DIALOG_RESOURCE_TYPE = "project-a/components/product/wizzard"; function isTargetDialog($formElement, dlgResourceType) { const resourceType = $formElement.find("input[name='./sling:resourceType']").val(); return resourceType === dlgResourceType; } $(document).on("dialog-ready", function () { const $formElement = $(this).find('coral-dialog form.foundation-form'); if (!isTargetDialog($formElement, DIALOG_RESOURCE_TYPE)) { console.debug("Skip the listener, not a ", DIALOG_RESOURCE_TYPE, " dialog."); return; } ... }); })(document, Granite.$);
As we can see these three steps will help to keep code clean and maintainable.