Hi all,
For a client we required some custom javascript to be executed when components are inserted, edited and deleted
For this we created our own clientlib and assigned it the following category:
cq.authoring.editor.sites.page
Full .content.xml file
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="cq:ClientLibraryFolder"
allowProxy="{Boolean}true"
categories="[cq.authoring.editor.sites.page]"/>
This clientlib contains a JS file which has some neat functions i pass along to the cq:listeners in the cq:editConfig file of various components.
Here is a short version of the JS file:
(function(window, Granite) {
"use strict";
const myClient = window.myClient || {};
const authoringActions =myClient.authoringActions || {};
window.myClient = myClient;
myClient.authoringActions = authoringActions;
const privateFunctions = {};
authoringActions.openEditDialog = function() {
etc....
};
authoringActions.refreshContentFrame = function() {
etc..
};
etc...
}(window, Granite));
Here is an example how we use it within a cq:editConfig of a component
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root
xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="cq:EditConfig"
cq:actions="[INSERT,EDIT,DELETE,COPYMOVE,PASTE]">
<cq:listeners
jcr:primaryType="cq:EditListenersConfig"
afteredit="myClient.authoringActions.refreshContentFrame"
afterinsert="myClient.authoringActions.openEditDialogRefreshOnSaveDeleteOnCancel"
afterdelete="myClient.authoringActions.refreshContentFrame"/>
</jcr:root>
This is the problem:
approximately 7 out of 10 times, when loading in the authoring environment the author is greeted with the message:
"An error occurred, please check the browser console for more details."
When checking the console we can read this:
Handler of component is invalid -> ReferenceError: myClient is not defined
at eval (eval at ns.util.sanitizeCQHandler etc....
As this occurs are random this tells me that this is a raise condition
It is probably caused by AEM checking if the validity of the configured cq:listeners to see if the javascript that needs to be executed actually exists.
During this check, the clientlib apparently was not initialised yet.
Funny thing is, when the author start authoring, all javascript functionality assigned to the listeners work just fine even if the error was given prior.
The ideal solution is to find a way to have the Javascript from this clientlib fully initialised prior the sanitizeCQHandler did it's thing (perhaps we can change to another category?)
But i don't mind turning sanitizeCQHandler off (if possible) for these components as a fallback
Did you experienced this aswell? If so, how did you work around it?
Solved! Go to Solution.
Views
Replies
Total Likes
Hi @DennisAtDept ,
Yes switching the category from cq.authoring.editor.sites.page to cq.authoring.editor is a valid and recommended fix for the race condition you're experiencing. And since your clientlib only contains utility functions for cq:listeners, the side effects are minimal but it’s important to be aware of the trade-offs:
Benefits of Using cq.authoring.editor
1. Fixes the race condition:
- This category is loaded early in the authoring lifecycle before AEM processes cq:editConfig and cq:listeners.
- Your JS functions will always be defined when AEM validates the listeners.
2. Cleaner authoring experience:
- Avoids "An error occurred, please check console" message.
- Makes the authoring UI stable and predictable.
Potential Drawbacks (and how to mitigate them)
1. Risk - Editor UI Performance
Description - This category is loaded on every page in the editor (including templates, XF editor, etc.). If your JS grows large, it might slightly delay authoring boot time.
Mitigation -
- Keep your code minimal and specific only include listener utilities.
- Avoid bundling unnecessary 3rd-party libs here.
2. Risk - Over-broad Scope
Description - If your logic is specific to certain components or page types, it may load unnecessarily in unrelated contexts.
Mitigation -
- Wrap your functions in checks (e.g. if (Granite.author && window.location.pathname.startsWith('/editor.html/content/my-site/'))).
3. Risk - Global Namespace Pollution
Description - Since it loads globally, any badly scoped variables/functions could clash with other libs or AEM's internal code.
Mitigation - Namespace everything under window.myClient or similar. Don’t declare functions in the global scope.
Regards,
Amit
Switching the category from
cq.authoring.editor.sites.page
to
cq.authoring.editor
seems to have solve this issue. Any potential problems when doing this?
The clientlib will only contain functions to be called by the cq:listeners.
Hi @DennisAtDept ,
Yes switching the category from cq.authoring.editor.sites.page to cq.authoring.editor is a valid and recommended fix for the race condition you're experiencing. And since your clientlib only contains utility functions for cq:listeners, the side effects are minimal but it’s important to be aware of the trade-offs:
Benefits of Using cq.authoring.editor
1. Fixes the race condition:
- This category is loaded early in the authoring lifecycle before AEM processes cq:editConfig and cq:listeners.
- Your JS functions will always be defined when AEM validates the listeners.
2. Cleaner authoring experience:
- Avoids "An error occurred, please check console" message.
- Makes the authoring UI stable and predictable.
Potential Drawbacks (and how to mitigate them)
1. Risk - Editor UI Performance
Description - This category is loaded on every page in the editor (including templates, XF editor, etc.). If your JS grows large, it might slightly delay authoring boot time.
Mitigation -
- Keep your code minimal and specific only include listener utilities.
- Avoid bundling unnecessary 3rd-party libs here.
2. Risk - Over-broad Scope
Description - If your logic is specific to certain components or page types, it may load unnecessarily in unrelated contexts.
Mitigation -
- Wrap your functions in checks (e.g. if (Granite.author && window.location.pathname.startsWith('/editor.html/content/my-site/'))).
3. Risk - Global Namespace Pollution
Description - Since it loads globally, any badly scoped variables/functions could clash with other libs or AEM's internal code.
Mitigation - Namespace everything under window.myClient or similar. Don’t declare functions in the global scope.
Regards,
Amit
Hi @DennisAtDept,
I think you are right - here is why:
The cq.authoring.editor
category loads much earlier than cq.authoring.editor.sites.page
, which is page-specific and deferred until after the editor chrome and page frame are bootstrapped. This ensures your global object (window.myClient
) is defined before AEM tries to resolve listener handlers like afteredit
.
So yes - switching the category to cq.authoring.editor
prevents the race condition by guaranteeing earlier execution of your clientlib.
cq.authoring.editor
?Global loading:
This category loads on all pages in the editor (eg. sites, experience fragments, templates, etc.). If your JS is only needed for sites pages, this could be a mild performance overhead.
Editor performance:
If your custom code grows large or includes 3rd-party libraries, loading it early and globally might slow down AEM authoring UI initialization.
Potential collisions:
Since cq.authoring.editor
is shared among other libs, avoid defining broad globals or anything that could interfere with AEM’s native code.
Hi all,
Thank you all for your feedback.
All warnings are fair and are taken into consideration.
Indeed, to isolate the functionalities, we opted in to just use the clients name as the name of the main object all of our custom code will be assigned to. This should not clash with AEM OOTB functionalities in anyway. These functions are going to be used by most components if they need them and are not specifically created for single component or template.
The functions we create are very small and only really use available functionality within the Granite.author object with the exception to reload the ContentFrame.
While testing we did not notice any drawbacks and all seems to be working as intended.
Views
Likes
Replies