Tech Tips

How to Add Image Management to an AEM TouchUI Dialog: Tutorial

Hi guys! It’s been a long summer. We hope you enjoyed it despite the pandemic – had some rest, maybe travelled to fancy places and took some good photos.

Speaking of photos, hardly any website can do without images nowadays, and we as AEM developers work every day building image-rich web experiences. Many of the components we create have the “insert/upload” option for AEM images in Touch UI. There are multi-image components in AEM sites that offer multiple image slots for desktop, tablet, and mobile views. A Touch UI dialog must support basic image management, including picking from a file system, drag-and-drop, a preview box, and a clear button.

These options have always been present in AEM image widgets. However, there has always been a fly in the ointment. In Classic UI, we had the Html5SmartImage dialog component. Setting it up wasn’t easy. To provide a better image uploading experience, you had to supplement it with hidden fields and use custom client libraries. There was also an issue with placing several Html5SmartImage-s in one dialog tab.

Things got better with the introduction of Touch UI dialogs. Adobe’s stock component libraries, Coral 2 and Coral 3, offer some advanced tools for Touch UI image uploading and drag-and-drop. But the API remains somewhat sophisticated, there are many setup options, and they’re still difficult to work with.

We struggled before we added the image management facility in the Exadel Authoring Kit — part of Exadel Toolbox. Now it has a variety of tools to make image management in Touch UI dialogs much simpler.

The Options

To start with, there are at least three (probably more) different AEM components that deal with images.

First, we’ve got the FileUpload component, which belongs to the Coral 2 library. As you can assume from the name, it can be used to upload images. The widget comes bundled with image drag-and-drop, preview, and a clear button.

However it lacks a good path picker. A path picker is a common requirement for authors. We used to add it to the out-of-the-box components by hand (see this article on how our team did this). We also used to add a custom “Copy” button.

Second, there’s the FileUpload from the Coral 3 component set. You can find it in JCR under granite/ui/components/coral/foundation/form/fileupload. This one is new but quite limited in features. Technically, this is just a button that can be used to pick a file for uploading. You can only select a file from the local file system and put it directly into the AEM storage in a folder like /content/myFiles.

With Exadel Authoring Kit, you can add this file uploader to your image-powered Touch UI dialog with the @FileUpload annotation. However basic in look and feel, it helps to keep the code compatible because it matches the “conventional” Coral 3 component. It’s also useful because it can upload any kind of file, not just pictures.

The picture above is made up of just this much code:

@DialogField(label = "Image")
@FileUpload(
  uploadUrl = "/content/myContent",
  mimeTypes = {".jpeg", ".jpg"}
)
@ValueMapValue
private String file;
See more See less

Remember that the content you pick will be stored under the node specified by uploadUrl param. But the exact name of the file created will be the same as the name of the Java field (or the name parameter of @DialogField if you choose to redefine it).

Picking our favorite 

There’s another strong contender — the file uploader that lives in cq/gui/components/authoring/dialog/fileupload. This one has finally accumulated all the features we’ve been talking about: the fully functional “upload” button, the Touch UI image drag-and-drop area, and buttons for ClearPick (allows you to select a file from the AEM instance, such as from the DAM folder), and even Edit (lets you modify the image with native AEM tools).

Our team has used this option extensively in commercial projects, and it has proven reliable and effective. That’s why we offer it as the first-choice Touch UI dialog image widget in Exadel Authoring Kit.

This one is represented by @ImageUpload annotation. Your code will look like this:

@DialogField(
  label = "Image",
  description = "Pick an image from the file system"
)
@ImageUpload(
  allowUpload = true,
  fileNameParameter = "./photo/sub/node"
)
@ValueMapValue
private String file;
See more See less

You can upload images with this Touch UI image widget in much the same way as you would with the previous one. Just add allowUpload = true to the annotation. Again, the image binary is stored in the subnode named after the underlying Java field (or the name property of @DialogField).

When uploading files, remember that the name of the file will be stored in the property or node you have specified for fileNameParameter. Note that it is necessary to start the value with ./

If you provide a “plain” property name, it will just add a property to your component’s node. But if you specify something like fileNameParameter = “./pathTo/myFile”, under the current resource you’ll find the subnode pathTo and the property myFile in it — all created automatically as the dialog closes. This can be of use if you want to accumulate all the image-related properties (like alternative text, title, display styles, etc.) in a dedicated subnode.

Fiddling with the file references 

Though uploading images in AEM is fun, more often you would select pre-uploaded images from the DAM folder or just drag them onto the dialog from the side rail.

For this kind of action, we skip the file name, since there’s another important property — fileReferenceParameter. It defines the place where the paths of the images you select will be stored. As before, fileReferenceParameter = “./myImage” will simply produce the property named myImage in the same resource node as the component. But fileReferenceParameter = “./path/to/myImage” will provide a subnode (actually, two nested subnodes).

Interestingly, you have virtually no need for @DialogField(name=…) in this particular case. You can definitely use @DialogField to specify the label, description, “required” state, etc. However if you specify name as you do for other dialog fields, it will be ignored, and the image path will be stored in the property specified by fileReferenceParameter. And if you don’t specify fileReferenceParameter at all, the default parameter (named, literally, fileReference) will be in place.

However if you specify, for example, @DialogField(name = “image/”) — that is, a string ending with a slash — it will not be ignored despite what was said above. It will actually produce a subnode for the part before the slash. But again, so as not to get confused with different name variations, you can skip everything but the fileReferenceParameter. This is how it works in AEM 6.5.

Touch UI Image Drag-and-Drop without a Dialog

Dragging images onto a dialog window is a nice feature, but don’t forget you can also drag them onto the component itself without even opening a dialog. This is an out-of-the-box option for which you don’t need a Touch UI  image widget. Instead, you create a specific component configuration. Exadel Authoring Kit supports this through @EditConfig:

@EditConfig(
  dropTargets = @DropTargetConfig(
    accept = {"image/.*"},
    groups = {"media"},
    propertyName = "./path/to/image",
    nodeName = "image"
  )
)
See more See less

The propertyName param is not new. It is subject to the same rules as in @ImageUpload. But look at the required nodeName property; it has some additional meaning.

First, it defines the name of a node in the component’s config where the propertyName will be stored. This isn’t a major difference, since it could be named anything.  The most important thing is that nodeName determines a part of the class name of an HTML container within your component’s markup. If you specify something like  “image” here, the full class name will be cq-dd-image. If you put “myTarget”, the full class name will be cq-dd-myTarget, and so on.

The HTML element with this class will become the receiver of drag-and-drop actions. If you forget to add class=”cq-dd-something” in HTL, the “dialog-less” drag-and-drop won’t work.

You can have multiple @DropTargetConfig-s in one @EditConfig, with different nodeName-s specified. This way you can drag multiple images onto your component. Just add class=”cq-dd-something1″, class=”cq-dd-something2″… to different HTML parts of your multi-image component’s markup.

Integrating with Sling

Whatever annotation you choose, you can add it to the Sling model where it will be attached to the field reading the path value as a string from the JCR storage. Here is how you can define storing an image file reference in the subnode and retrieve it via the @ValueMapValue Sling injector annotation:

@DialogField(
  label = "Image",
  description = "Pick an image from the file system"
)
@ImageUpload(
  fileReferenceParameter = "./path/to/image"
)
@ValueMapValue(name = "path/to/image")
private String image;
See more See less

To sum up, you can use @ImageUpload for the modern feature-rich imaging experience, or the @FileUpload if you like it better. You can even switch to the older Coral 2 FileUpload, however this is not supported by the Exadel Authoring Kit out of the box. All you have to do, though, is add a custom annotation as described in the project’s documentation.

We hope this helps you use multi-image components more frequently and improve your AEM Touch UI dialogs with imaging facilities! Do not hesitate to contact us, the Exadel Authoring Kit team, through our GutHub repo! See you later!


Authors: 
Stepan Miakchilo, Aliaksei Charniakou, Liubou Masiuk