Starting from AEM 6, there’s a cool functionality called Sling Resource Merger. It allows us to override a component dialog of some parent (super) component with a less XML code.
Let’s demonstrate it on some example. Suppose that we have a component with the following dialog definition:
<?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" jcr:primaryType="nt:unstructured" jcr:title="Parent Component" sling:resourceType="cq/gui/components/authoring/dialog"> <content jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container"> <layout jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/layouts/tabs" type="nav"/> <items jcr:primaryType="nt:unstructured"> <generalTab jcr:primaryType="nt:unstructured" jcr:title="General" sling:resourceType="granite/ui/components/foundation/container"> <layout jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/> <items jcr:primaryType="nt:unstructured"> <columns jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container"> <items jcr:primaryType="nt:unstructured"> <title jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/form/textfield" fieldLabel="Title" name="./title"/> <subtitle jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/form/textfield" fieldLabel="Subtitle" name="./subtitle"/> <titleFilter jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/form/textfield" fieldLabel="Title Filter" name="./titleFilter"/> <showSeriesFilter jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/form/checkbox" name="./showSeriesFilter" text="Show Series Filter" value="true"/> <seriesFilterTitle jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/form/textfield" fieldLabel="Series Filter Title" name="./seriesFilterTitle"/> </items> </columns> </items> </generalTab> <advancedTab jcr:primaryType="nt:unstructured" jcr:title="Advanced" sling:resourceType="granite/ui/components/foundation/container"> <layout jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/> <items jcr:primaryType="nt:unstructured"> <columns jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container"> <items jcr:primaryType="nt:unstructured"> <advancedConf1 jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/form/textfield" fieldLabel="Advanced Config 1" name="./advancedConf1"/> <advancedConf2 jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/form/textfield" fieldLabel="Advanced Config 2" name="./advancedConf2"/> </items> </columns> </items> </advancedTab> </items> </content> </jcr:root>
The component dialog has two tabs with four and two fields, respectively. Now let’s define a new component by extending the existing one. All fields from General tab should appear in a dialog of the subcomponent but two of them, showSeriesFilter and seriesFilterTitle. Also, Advanced tab is not needed for the subcomponent.
The dialog definition should look like this one:
<?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" jcr:primaryType="nt:unstructured" jcr:title="Subcomponent" sling:resourceType="cq/gui/components/authoring/dialog"> <content jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container"> <layout jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/layouts/tabs" type="nav"/> <items jcr:primaryType="nt:unstructured" sling:hideChildren="[advancedTab]"> <generalTab jcr:primaryType="nt:unstructured" jcr:title="General" sling:resourceType="granite/ui/components/foundation/container"> <layout jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/> <items jcr:primaryType="nt:unstructured"> <columns jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container"> <items jcr:primaryType="nt:unstructured"> <showSeriesFilter jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/form/checkbox" sling:hideResource="{Boolean}true"/> <seriesFilterTitle jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/form/textfield" sling:hideResource="{Boolean}true"/> </items> </columns> </items> </generalTab> </items> </content> </jcr:root>
Because there’s the inheritance relationship between these two components (defined by sling:resourceSuperType property), Sling Resource Merger will merge the two dialog definitions. sling:hideResource property is the instruction for the merger to hide the corresponding property in a result of the dialog definition merge, and sling:hideChildren property causes that the merger will hide the inherited Advanced tab. All other fields will be copied during the merge.
Before the merger has been introduced, a developer had to do the following:
- create the subcomponent dialog definition by copying/pasting the parent component dialog definition
- do the necessary modifications (for this sample, remove all unwanted fields from General tab and remove Advanced tab definition)
You can find the detailed documentation about Sling Resource Merger here.