BREAKING NEWS: Exadel named a Leader in this Forrester Agile Software Development Service Providers report... Learn more!  

Classic to Touch UI Migration for AEM: Multifields

 
 
 

In our previous post on Classic to TouchUI migration we focused on one quirk of this migration, Page Properties. In this post,  we focus on one more quirk about what are called multifields.

Adobe Experience Manager provides a lot of different out-of-the-box fields for creating component dialogs. Multifield is one of them. Multifield is used for repeated instances of the same fields or groups of fields, allowing us to add, reorder, or remove its items. During the migration to TouchUI, we found out that this field is quite challenging in trying to ensure backwards compatibility. Let’s look at the differences between ClassicUI and TouchUI multifields.

First of all, it depends on the complexity of a multifield item. Let’s assume we have a simple multifield where each item is a  text field. In this case, the content will be stored as a multi-string value.

But what if there are several types of field in a multifield item? Then it depends on whether we’re talking about a ClassicUI widget or a TouchUI component.

In the case of ClassicUI, the developers would usually have had to create a custom xtype in order to save several fields into one. The data was usually stored in JSON format.

For TouchUI, a CoralUI multifield component has out-of-the-box support of multifield items with several fields (i.e., composite multifield). But there is a catch. They are stored in subnodes under the component.

That causes a huge issue with backwards compatibility and migration of components with such multifields to TouchUI.

Possible Solutions

So what can we do with this issue in TouchUI? We found several approaches proposed by AEM community members.

Option 1: Update the component’s code to retrieve data from nodes instead of JSON and create a script to convert all JSON data and save it into nodes, as suggested in this thread.

Pros:

  • We don’t have any problems with subsequent components created after migration
  • All data is stored in the same format compatible with the Coral3 multifield

Cons:

  • Changing large amounts of content via script in a production environment can be risky

Option 2: Switch to Coral2 multifield and use the ACS commons Multifield Extension.

Pros:

  • No changes to the content
  • No changes to the back-end multifield processing logic

Cons:

  • The ACS commons Multifield Extension is officially deprecated
  • The Multifield Extension does not support Coral3 multifield, so this is a short-term solution, which will require additional migration to Coral3 after Coral2 is deprecated

Option 3: Create a custom component that saves multifield items into JSON nodes, as suggested in this adaptTo() talk.

Pros:

  • No changes to the content
  • No changes to the back-end multifield processing logic

Cons:

  • In the long term this approach will require more maintenance and will never be fully compatible with OOTB Coral multifield

Our Solution

After weighing all the pros and cons of these solutions, we came to the conclusion that none of them are 100% suitable for us, so we came up with our own approach.

  1. The Coral3 multifield component is extended to provide backward compatibility with legacy JSON data
  2. New data is always saved into nodes
  3. When opening an old instance of component with legacy data, JSON is parsed into form fields
  4. When saving such a component, legacy data is replaced by nodes

This strategy gives us the following advantages:

  • No scripts and no risky changes to the content—the data will be gradually updated when the content is changed
  • New components are compatible with OOTB multifield, so at some point in the future we can potentially remove this customization and move back to Coral3 multifield

In order to implement this approach, first we need to create a new form component that extends Coral3 multifield. To achieve that, we need to point the component’s sling:resourceSuperType to granite/ui/components/coral/foundation/form/multifield.

Then, we modify the existing multifield so that it parses the legacy JSON structure and retrieves all existing fields. There is one specific edge case that we needed to cover. Some legacy components had only one field in the item, but still saved their structure into JSON. The resulting data looked like this:

./links
String[]
{"url":"https://www.google.com"}{"url":"https://www.adobe.com"}{"url":"https://www.example.com"}

Such fields should be converted to simple TouchUI multifields. Here is what the component’s renderer.jsp file looks like (some parts omitted for brevity):

In order to retrieve multifield data in component model/wcmUse class, we also need to check whether the data is stored in nodes, a JSON array, or as a simple array. That’s why our MultifieldUtils class also contains a couple of methods that allow us to consistently work with stored data and get a list of valueMap objects independently of how data is currently stored in JCR.

BREAKING NEWS! Want to test new technologies like blockchain, AI, mobile, chatbot, and machine learning models? Learn about our Innovation Cloud.