-
Notifications
You must be signed in to change notification settings - Fork 0
Complex multi layered components authoring
Once in a while during CQ/AEM app development you need to create a very complex component. This might mean a lot of options that simply do not fit nicely into one dialog. And even as they finally do - the amount of settings is overwhelming and hard to grasp for an author at first sight (and then - at the second, the third... - also).
Other times - it might be yet another non-trivial element of a frontend puzzle that is packed and dense already, but you still need to overlay it with e.g. paragraph system. With the increasing amount of editing related elements the page becomes hard to read and custom author mode clientlibs tweaks start to interfere with the publish CSS and JS of the page itself, causing mess and making life of frontend developers in the project miserable. I'm going to take on this general case and suggest a solution.
Let's examine some concrete examples. I've come across them and have also struggled with some custom author mode solutions already in place. As these were causing new issues (apart from creating a hard to read author interface and not being intuitive) - I had to come up with something new. At least for me back then it was new. You can easily skip this part if you already understand the issue posed above.
Quite common component with different variations needed in most corporate websites within some general pages like homepage, products list, news list, etc. There is some scripting involved of course to make the images slide, maybe a tricky CSS styling. Such component causes a discrepancy between author mode and final publish view. On one hand we have this densely packed view of many elements that share the same piece of viewport in the publish mode. But on the other - we would like it also to be configurable for the author, so basically we need to break this packing - we need to separate individual elements.
The single images (or whatever content an individual element represents) might come from the local page resource i.e. be authorable in the current page. This situation presents some challenges. In a simple case we can use a dialog widget for building image gallery, but for complex cases (complex individual components and/or of more than one type) a better solution is to use a paragraph system to build the list.
Another common component for content rich brand websites. A complex popup menu with lots of hidden panels that show up upon hovering with the mouse pointer. The content of hidden panels can be anything actually. You can imagine adding custom column layouts with separately designed paragraph systems for each of them. And every column might contain different components - both custom configured in place, e.g. a set of custom links.
Now imagine integrating this kind of component nicely within a rich already end user frontend interface tangled with AEM markup and scripting. It can become hell. Is there a solution that improves both the developer and author experience?
So in general then the problem occurs when the final rendition of the component in publish mode does not allow a straightforward configuration in author mode. And it requires a different view for the editor compared to what the end user shall see. The simplest and most common general case is a compound of a varying number of simple elements.
Then the natural way of handling them in AEM is usually a paragraph system. But it's much easier to use a vertically expanding parsys than trying to make it work horizontally.
So what possible solutions do we have for such a setup? I've seen a couple in my career.
The first approach is the easiest yet naive. We simply show the author a different view of our component. In publish we present the final rendition view, but for editing we include the parsys of partial items vertically.
But imagine what happens when an author wants to add several compound components and all of them are unfolded like that. The page becomes unnecesserily elongated and it becomes unbearable for the content entry staff.
Another option is to add some special action buttons (to the editbar for instance) on the compound in the author view that will fire custom JS that will expand and collapse the views basically switching between the two images above. It's actually not bad from author experience point of view, but requires usually a custom FE author code for that switch that depends on the compound. And possibly any changes to FE JS will require an update here as well.
Third approach I've seen would be a reference. Let's say we want to have a page /content/page that we want to configure with a compound under /content/page/jcr:content/content/compound. We then create a pool page under /content/pools/compound where we allow the authoring of our complex component. Then the /content/page/jcr:content/content/compound simply holds a reference to the pool page and renders the compound in publish view already.
It will work if only we put the work needed to connect the gears properly. And indeed one can master the general approach to allow a developer to do it in a couple of established steps. But I don't personally like this approach - it's a workaround, not a solution. First of all it causes the data stored to be incoherent. What should be local does not stay local anymore. The reference causes the tree of resources to be more entangled. And it does not have neither a semantical nor a structural ground to base on. It's simply done so that we can edit the component.
In a case when a single component instantiation is meant to be used in a couple of independent pages it makes sense indeed - there's a business value to the referencing approach. The author gains something then. And that's the purpose of introducing Content Fragments and Experience Fragments. But these are not a workaround, these are features.
The reference approach adds another layer that could be avoided otherwise. You need to handle the path correctness. You can't easily check the referenced component's validity. You need to remember to put the pools in your filters in case you want to create a dontent package with the page inside. You need a separate page for the pool, the compound component plus the referencing component. You need to handle the designs of all of them then: you can't simply say where the referenced compound is allowed, you need to work it out within the referencing component. As I mentioned - it is doable, but adds the kind of complexity I don't like - since it all seems like a workaround anyway...
Option number four would be using a multifield or multicompositefield for the individual items. But imagine handling many non-trivial such sub-components in a simple list within a single dialog. And if they have to contain, let's say, some links or buttons? And what if you want them to be of totally different types? E.g. a video, an image, an iframe - all within your slides of your slider. And God forbid if you use the ugly JSON approach storage within JCR...
The best approach I've seen out there is actually something I cannot reproduce right now... The main component's dialog was equipped with a widget of an unknown (as of now) xtype to me. The widget allowed a list of sub-components and direct opening of their dialogs from within the main dialog. Might be it was a custom one or maybe I've missed it somehow from the list (slideshow xtype seems too limited).
Here are the tools that I would use:
Please familiarize yourself with parsys and ComplexComponent to better understand those above.
One could easily use the lib developed within special modes implementation to introduce a construct of aspects for a given component. Just the way author mode allows e.g. preview + edit + design + etc. modes for the whole page - the complex template allows a simple mechanism for handling different views of a single component. complex.js' toggleMode function permits any selector as targetMode. The things to do would be to:
- add an approppriate selector to parsys,
- add a cq:editConfig entry with toggleMode,
- add the aspect selector inside the component in question.
There's also actually a ras initial implementation for a dedicated aspect mode based also on the parsys and showcased in a raw example, but it still needs some work.