Stefan Cameron on Forms
Building intelligent forms using Adobe LiveCycle Designer

Pre-Process Web Service Responses

Connecting to a web service usually means using import bindings to capture the response but what if you wanted to do something special with the response? What if the response wasn’t exactly correct for merging into your form (e.g. you just wanted to extract a part of the response and push it into your form somewhere)?

You could still use import bindings (set using the “Object palette > Bindings tab > Import/Export Bindings property”) but then you might have to hide most — or all — of those fields if you didn’t want to expose them. You would wait for the web service data connection to execute, then find the field that contains the piece of data you want and set it where it needs to go. This isn’t ideal, however, because Designer doesn’t expose any events, in the Script Editor, that would let you know that you now have data from the web service response in your form. Furthermore, having those extra fields around could add a lot of unnecessary weight (read: file size).

postExecute event

Unless you have studied the XML spec or deciphered its existence from the LC Designer ES Scripting Reference, you most likely don’t know about this event because Designer’s Script Editor palette doesn’t expose it. It’s purpose is to allow for post-processing of a web service response after a particular data connection is executed. The response data is temporarily stored in

xfa.datasets.connectionData.{DataConnectionName}

for the duration of the data connection’s PostExecute event.

Since it’s not exposed in the Script Editor, you have to go to the XML Source in order to set it on a form object — typically a subform. What follows is the XFA definition for the WebServiceDC data connection’s PostExecute event:

<event activity="postExecute" ref="$connectionSet.WebServiceDC">
    <script contentType="application/x-javascript">
        // do something...
    </script>
</event>

Note that I said this was the PostExecute event for the WebServiceDC data connection. The PostExecute event on its own — without a ref attribute that specifies the data connection to which it pertains — is of no use. In this case, the ref attribute specifies the WebServiceDC node inside the form’s connectionSet DOM (where web service data connections are defined). (Normally, the ref attribute has a value of “$”, which means “this”, since the event usually pertains to the form object on which it is defined.)

If you combine this with the ability to get web service response data without merging it into the form (either by not checking the “Object palette > Execute tab > Re-merge Form Data property” of the execute button for the data connection or you call xfa.connectionSet.{DataConnectionName}.execute(false)), you can essentially call a web service, get data back and do whatever you like with it.

Sample Form

To demonstrate how this works, I’ve created a sample form that has two web service data connections. It may take some time to open in Designer depending on how fast Designer can download the WSDL files from the two web services.

The first one, EchoEmployee, submits data from the top 4 fields and, using the PostExecute event, adds an item for each piece of data received in the response inside the list box. The following screen shot shows a sample result:

The second one, ConvertTemperature, obtains the conversion of the specified temperature from the web service response and displays it in a message box.

Download Sample [pdf]

Sample Minimum Requirements: While I developed the sample using Designer 8.2 and Acrobat 9.1, I have set the compatibility level to Acrobat/Reader 7.0.5 since this should work back to that version however I have not tested the form with anything earlier than 8.2/9.1.

Update (Sep 2, 2010): Note that the “Echo Employee” web service is no longer operational. This means that the first web service connection in the sample form can no longer be executed. The script is still valid, however, and serves as a good example. The second web service, “Convert Temperature”, is still operational.

Pre-Processor Library Snippet

In an effort to ease the pain of having to edit the XML Source, I have created an Object Library Snippet (XFO) that you can use to easily plug into this functionality:

Library Snippet [xfo]

In order to use it, you will have to save it to your Object Library’s Custom snippet folder which, depending on whether you installed Designer on XP or Vista, will be in one of the following locations:

C:\Documents and Settings\{username}\Application Data\Adobe\Designer\{version}\EN\Objects\Custom

C:\Users\{username}\AppData\Roaming\Adobe\Designer\{version}\EN\Objects\Custom

Once inserted into your form, the snippet will look like this:

By default, it’s set to work with a web service data connection that is named “WebServiceDC”. When that data connection’s PostExecute event is fired, the script inside will find the response data and call the processResponse() function defined on a script object that is included in the snippet (which is essentially a subform). Finally, the subform hides itself when the form is initialized so you don’t have to worry about hiding it yourself.

Now all you have to do is put script in the processResponse() function using the Script Editor!

If you need to use a different data connection name, you’ll have to go to the XML Source and make two modifications, highlighted here:

The first modification is to the ref attribute of the <event> node that defines the PostExecute event and the second is in the script itself where it extracts the XML of the response.

Sep 2, 2010 — Added note that “Echo Employee” web service is no longer operational which affects the first of the two connection samples in the sample form.


Posted by Stefan Cameron on March 23rd, 2009
Filed under Data Binding,Designer,Events,Scripting,Tutorials,XFA
Both comments and pings are currently closed.

7 Responses to “Pre-Process Web Service Responses”

  1. Norbert on July 30th, 2009

    thanks for this article, works fine!
    but what if the result of the service is an array and i want to read the single items??

    please help me, i tried to populate a drop down list box (worked via binding).
    but if the answer of the webservice contained more information i wanted to store it in a table and i failed…

  2. Norbert on July 30th, 2009

    function processResponse(rootXml, soapFault)
    {
    KUNNR.clearItems();

    if (rootXml)
    {
    Name.rawValue = rootXml.customersByIdResponse.return.name.value;
    ORT.rawValue = rootXml.customersByIdResponse.return.city.value;
    LAND.rawValue = rootXml.customersByIdResponse.return.country.value;
    STRASSE.rawValue = rootXml.customersByIdResponse.return.street.value;
    }
    else if (soapFault)
    {
    //ListBox1.addItem(“Fault code: ” + soapFault.code);
    //ListBox1.addItem(“Fault message: ” + soapFault.message);
    }
    }

    “return” is the array and i populate the ddlb with “name” and “id” but want to read the “city”, “country” “street” later (when the user selects one entry of the dropdownlistbox)

  3. Stefan Cameron on August 7th, 2009

    Norbert,

    If rootXml.customersByIdResponse.return is an “array”, then I’m assuming that rootXml.customersByIdResponse has multiple “return” nodes underneath it. In that case, you would do something like this:

    // JavaScript:
    
    utils.itemMap = new Object(); // initialize map
    KUNNR.clearItems(); // initialize list
    
    for (var i = 0; i < rootXml.customersByIdResponse.nodes.length; i++)
    {
        var returnNode = rootXml.customersByIdResponse.nodes.item(i);
    
        // add new list item setting name as item text (displayed)
        //  and id as item value (hidden)
        KUNNR.addItem(returnNode.theName.value, returnNode.theId.value);
    
        // add entry to itemMap for this node which is an object that
        //  contains three properties: city, country, street
        utils.itemMap[returnNode.theId.value] =
            {city: returnNode.city.value, country: returnNode.country.value,
            street: returnNode.street.value};
    }

    Later, in the KUNNR's Change event, you can retrieve the city, country and street info like this:

    // JavaScript:
    
    var selectedId = this.boundItem(xfa.event.newText);
    var itemInfo = utils.itemMap[selectedId];
    
    xfa.host.messageBox("Selected item info: " + itemInfo.city + " " +
        itemInfo.country + " " + itemInfo.street);

    Notes:

    • I changed "id" and "name" to "theId" and "theName" because using "id" and "name" and node names can cause conflicts because these are also properties on almost all XFA objects.
    • I'm assuming you have a Script Object named "utils" in which there is a declaration of a variable named "itemMap": "var itemMap = null;" Variables in Script Objects keep their values as long as the Form DOM isn't reset.
    • On an object variable, obj["string"] adds a new dynamic property to that object that is named "string".
    • You can create new objects with dynamic properties with the following syntax: {propertyName: propertyValue, ...}

    Aug 26, 2009 — Fixed script by adding ".value" property accessors on node properties within the "returnNode" object.

  4. Norbert on August 26th, 2009

    stefan,
    thanks for your reply! working good till to the point where i want to adress the fields of the returnNode!
    scripting stops at “KUNNR.addItem(returnNode.theName, returnNode.theId);” and if i drop it, teh “utils.itemMap” is empty, too.
    if i try with messages he declares returnNode.city beiing an “xfa object”, but returnNode.city.value is “null”

    thanks in advance!

  5. Stefan Cameron on August 26th, 2009

    Norbert,

    I’m afraid I forgot to access the “value” property everywhere in my script (from comment #3 above) where I access a node property in the “returnNode” variable.

    Thanks for pointing this out to me. I have updated the script in the comment with the changes.

  6. Norbert on August 31st, 2009

    Hi stefan,
    works great!!! Thanks a lot, if you ever visit vienna send me a mail!

    br
    norbert

  7. Justin on October 29th, 2009

    Hi Stefan,
    I recently used your pre-processor snippet in a government form I built to call a web service. It was very easy to follow and to use. Would you be able to confirm for me that given the return of web service call triggers an event that the actual web service call is asynchronous? I actually make the call right before I submit the form to our livecycle server however I noticed that we won’t always get data populated. So does the javascript call the web service and then continue on execution, or does it actually stop and wait for a response from the web service. Is there a way to make the web service call synchronous?

    Regards

    Justin