Returning Multiple Values from dynamically-created AEM Fragment

By 4Point

How do you return multiple values from a dynamically-created AEM fragment? More specifically, return more values from the fragment than there are visible controls. Simple… well, kind of simple.

 

While developing the 4-FLO application, a dynamic form-based workflow definition and monitoring solution, a requirement existed to enter one or more users to participate in the defined workflow using a form fragment. The fragment needed to allow for searching user names by entering characters and displaying users with those characters anywhere in their common name. The user list will be retrieved from the AEM server using a REST call to a custom endpoint. To do this, a fragment was created to encapsulate the UI to enter & display the participant and perform the web service call.

 

When returning the user information from the fragment to the hosting form, specific data elements have to be returned to assign an AEM task to that user and to notify the user via email; just the user’s name is not sufficient. We will also need the user’s email and principal id. Those additional values, however, were not to be shown in the fragment.

 

The main problem that we encountered while developing this fragment was how to retrieve multiple values from a fragment that contains only one field; name. Another problem was how to reference the fragment’s controls given that we may have multiple participants (one fragment per); in this scenario the fragment could not use global Ids to identify its destination field.

 

To resolve this issue, we experimented with ways of having the multiple values in a delimited list within the single name textbox control. This, however, exposed the user’s principal Id and email to the user entering the participant information. They could potentially change these values and affect the orchestration that assigns the tasks to individual participants. It also might confuse users as the principal Id is a GUID and our users would be expecting only the participant’s name.

 

To resolve these issues, we added hidden fields to the fragment to hold the principal Id, email, user type (e.g., USER or GROUP) and whether the user name in this fragment had changed.

 

 

Now we have a location to store all the data elements with all of them hidden except the name. We still have a problem: given that the fragments are added dynamically and given that more than one of these could exist on a single Adaptive Form, how do we tell the fragment’s code handling the web service’s response the name of its destination fields? (When adding the fields dynamically, the names of the fields are assigned by AEM when the controls are created. Nothing is known about those names until the fields are created when a new participant is added to the workflow.)

 

How do we resolve this issue?

 

Before we can start to describe how this was resolved, understanding the difference between a non-rendered Adaptive Form’s structure and a rendered Adaptive Form’s structure is needed.  A non-rendered Adaptive Form’s structure defines how the form will behave, while a rendered Adaptive Form’s structure defines how the form is behaving within a browser.  A rendered Adaptive Form has elements stored in a browser as node elements.  These node elements can be extended to allow custom attributes and associated values.

 

Now to how it was resolved.

 

During initialization of the fragment, the Object Ids of the various hidden fields are stored within the component. They are stored as attributes within a node that represents the custom component.  This was accomplished by using a custom library function called “defineResultsObjects”.  The implementation of this call and function are shown below.

 

The custom component’s initialization script:

 

defineResultsObjects ( this.somExpression, principalId, email, type, previousName )

 

The custom library function:

 

defineResultsObjects = function( srcSomExp, principalIdObj, emailObj, typeObj, previousNameObj )

{   var srcNode = window.guideBridge.resolveNode( srcSomExp );
      previousNameObj.value = srcNode.value;

      srcNode.setAttribute( principalIdObj, "principalIdObj" );
      srcNode.setAttribute( emailObj, "emailObj" );
      srcNode.setAttribute( typeObj, "typeObj" );     }

 

When a participant (fragment) is selected, the additional information are set into multiple fields using the stored attributes’ values.  For example, when the participant’s principal Id is to be set into its “Principal Id [hidden]” field, the custom component’s “principalIdObj” attribute’s value is read (this contains the object id of the “Principal Id [hidden]” field) and then used to define the object id’s value as shown below:

 

var principalIdTarget = srcNode.getAttribute( "principalIdObj" );
principalIdTarget.value = value;

 

An additional complication was caused as not all browsers fire events at the same time or in the same sequence. Originally, we used the name textbox exit event to check if a user was selected from the list (populating the hidden fields if it was). However, in some browsers the select (user) event fires after the exit event, meaning the user was not selected when the exit event fired. To circumvent this we added a changed group element to the hidden controls (shown above as “Changed [hidden]”). We set this element to “Yes” if the selected name has changed. This allows for the determination of a name change outside of specific events.

 

The use of hidden fields and node attributes to store object ids allows for a clean, self-contained way to return any number of values from dynamically-created fragments. We hope that this example will help you in your AEM Forms authoring.

 

Need a hand?
Contact Us