Building an AEM Authoring Component out of HTL/Sightly; no JSP required!
Adobe gives us a ton of authoring components out of the box!
I mean, just look at them all in CRXDE š²!
If youāve spent any time on an AEM project youāve no doubt composed component authoring dialogs using: Textfields, Switches, Multifields, etc. Adobe does a great job of providing almost everything a developer could need!
Occasionally though, weāll need something a little more custom and on those occasions, datasource takes care of me 95% of the time.
For example, letās say we have a Button/CTA component that needs to open up a modal/dialog. We can easily build a list of modal components on the page using a servlet and then provide that list via datasource:
<modalid
jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/select"
fieldDescription="When clicked open Modal with corresponding id."
fieldLabel="Modal ID"
name="./modalId">
<datasource
jcr:primaryType="nt:unstructured"
sling:resourceType="apps/mysite/datasource/modalsOnPage"/></modalid>Straightforward and easy for a Content Author to use, right?
This article is for us 5%āers who need something truly custom!
In my case, I have an SVG Sprite that contains all of the siteās iconography. If you arenāt using SVG Sprites (or arenāt familiar with the term), CSS Tricks is a great place to start but the gist is that you should probably be using SVG sprites over icon fonts.
Anyway, I needed a list of links where I could assign an icon to each link (if the author wanted). I didnāt want to display all icons, just ones appropriate for links. They also needed titles, just to help describe what the icon represented. The UI didnāt need to be anything special and I wanted it to fit with the CoralUI aesthetic so using a Coral.Select makes sense here.
Ultimately, this is what the end product looked like:
But before I could get there, I needed to figure out how to build authoring components. After some Google searching (and almost always ending up on the terse AEM docs or support forms) I gave up and decided to jump into the JCR and just look at how the text field works.
A render.jsp huh? Weird. So I looked for other, newer components. Same thing. Every authoring component was composed of a JSP. Even though HTL is the āpreferred and recommended server-side template system for HTML in AEMā, all authoring components are built with JSP.
Why? Can we not use HTL to build authoring components? I scoured the internet for answers, but came up empty until I noticed a note on the Creating a New Granite UI Field Component doc page:
So I created an HTL component and tried it out! I looked at some other examples and quickly threw together an empty Coral.Select in the HTLā¦
⦠and I found out the docs were right! I had no easy way to get the value supplied from a content author. The properties object referenced the attributes on my XML tag:
So, I could create the entire UI for the component, but there was no way for me retrieve the saved JCR value supplied by a content author. Every time a content author opened the dialog, the component would act as if it had never saved. Obviously this was not a tenable solution.
So, I referred back to the docs (and looked at a few more JCR components for good measure) and found that this is the āmagicā that JSP uses to pull in the JCR value for an authoring component:
So, theoretically all we need to do is gain access to that Field.class attribute on the request and then provide our components name (properties.name). So I attached a Sling model and used the debugger to peer inside the request attributes looking a āField.classā to see if I could find my missing JCR data.
No dice. I was about ready to give up and submit to my JSP overlords when I reached out to my brother Tim Solum, who is a much stronger Java developer than I am (Iām supposed to be the Front-End AEM guy after all). After some additional poking around with Tim, we found my missing JCR data under FormData.class.
How/why did it change between the JSP and Sling Model? I have no idea. I chalk it up to AEM magic but if you have a better answer sound off in the comments š!
The resulting Sling model boiled down to a single reusable method that would grab all values for a given authoring dialog request:
From there, we could easily grab values for a given field like so:
data-sly-use.dialogvalues="SITE.models.DialogValues"
value="${dialogvalues.values[properties.name]}"So thatās basically it! The rest of the icons I pulled in with Ajax and some JavaScript doc parsing (told you I was the Front-End). If you prefer, you could definitely parse the SVG Sprite within the Sling Model and return a Title/Sprite breakdown that way but we have HMR supported builds and I didnāt want to have to rebuild the Front-End and toss the Sprite in the JCR in order for new icons to show.
Iāll update this article later with a few Github gists showing off all the source files so you too can be the proud owner of a custom, filterable icon select component!
Update: Hereās the Gist.
If anything is unclear, let me know below and Iāll try to clear it up. Otherwise, thanks for reading!
