CRM and CX Blogs by SAP
Stay up-to-date on the latest developments and product news about intelligent customer experience and CRM technologies through blog posts from SAP experts.
cancel
Showing results for 
Search instead for 
Did you mean: 
Felix_Wyskocil
Product and Topic Expert
Product and Topic Expert
In my live sessions about print form adaptation with the Adobe LiveCycle Designer, data binding is a frequently requested and crucial topic. Especially in scenarios with complex tables and multi-level data structures. That’s why I decided to underline the sessions with some blog posts.

Most topics of the live sessions and blogs focus on the Adobe LiveCycle Designer (ALD) itself. So, they are applicable for several SAP cloud solutions where Adobe Document Services (ADS) are used. For system-related topics, I refer to either SAP Sales/Service Cloud (in former times SAP Cloud for Customer, C4C) or SAP Business ByDesign (ByD). Print form maintenance and output management is handled similarly in these two solutions.

I recommend reading this blog series in the order as stated below. You can find the registration information for my live sessions at the bottom of this blog.

List of print form blogs:

Simple Tables


Let's start with one of the easiest cases: A simple table. Tables are usually used to display repeating content. We typically have a header row with column captions and a body row that is repeated per data item.

Let's have a look at a very simple and basic table with three columns:


Simple Table


The body row plays the most important role here with the two settings at the Object-Binding palette that are highlighted in the screenshot:

  • The binding path is set to $.DeliveryNote.Item[*] where [*] indicates that the Item node can occur multiple times. This is added automatically when selecting the Item node from the binding menu. The Designer knows about the multiplicity of nodes due to the data connection (assigned xsd files).

  • Activating Repeat Row for Each Data Item enables the body row to be repeated for each occurrence of the Item[*] node.


After the body row is set up correctly, we can concentrate on the cells that finally show the data. They will be bound to sub-elements of the Item node with a relative binding path. Before looking at the binding itself, let's first have a look at an excerpt of the XML to see the data structure:


Excerpt of the first Item from the data XML


The highlighted elements are the relevant ones for our scenario. That means the binding of the cells looks as follows:

  • Text Field colIndex: $.ItemID

  • Text Field colProduct: $.ProductName

  • Decimal Field colQuantity: $.DeliveryQuantity.Quantity


The binding paths are relative because we have bound their parent control (the body row) to the XML parent node Item[*]. If you would see absolute paths here (starting with $.DeliveryNote), you should double-check the binding of the body row again!

While the colIndex and colProduct cells are implemented as text fields to show the plain text coming from the data source, colQuantity has been modelled as decimal field to demonstrate number formattings: When displaying numbers, we usually want to apply a certain number formatting that fits to the locale of the recipient and the use case, meaning controlling the appearance of the decimal and thousands separator or how many decimal places should be displayed. This can be achieved by using a numeric or decimal field instead of a regular text field, and applying a numeric pattern on the Object-Field palette.

Another aspect when displaying quantities or currencies, is the Unit of Measure (UoM): In the XML above we can see that we have additional information about the Unit of Measure available for the quantity, such as the full unit name inside the QuantityTypeCodeName or the abbreviation inside the QuantityMeasureUnitCodeName that are both language-dependent, meaning they come in the correct language for the respective recipient.

Keep in mind that the cells must be some sort of text field (numeric field, decimal field, ...) in order to be able to bind them to the data source. The pure Text control is for static text only. When generating the table from the menu Table -> Insert Table it usually consists of static Text controls that cannot be bound right away. However, for the header row static Text controls are ok.


Static Text controls on item level cannot be bound to the data source.


With the body row and the cell fields bound to the data source, we can preview the print form and see how the rendered table looks in the generated PDF:


Simple Table rendered with two items.



Repeating Subforms


It doesn't always need to be a table. In the first blog with the basics, we have used a subform as a container and have bound it to an address structure. We can use subforms for repeating data, as well. This can be handy if you prefer a layout that's a bit different from the typical rows/columns table style.

In the following example we display the product names of all items as a list. For that, the subform frmProduct has been bound to the $.DeliveryNote.Item[*] node and is allowed to be repeated. The text field txtProductName is bound to the $.ProductName node:


Simple Product List based on a repeating subform in the Designer.


Of course, we could have placed more fields within the repeating subform and nested them according to the desired layout. But let's keep it simple for this example. The resulting preview could look like this:


Preview of a simple product list, based on a repeating subform



Bind Once Limitation


IMPORTANT REMARK: If you try to rebuild the examples shown here, and you add the subform based product list underneath the simple table, you will probably run into the issue that the product list doesn't show any items, although you have bound everything correctly. To double-check this, you could change the sequence of the table and the product list. And guess what! The product list on top would work and the table below wouldn't show items anymore?


There's a simple reason: Imagine repeating data nodes are placed in a queue and every instance of a bound form control fetches an entry of the respective queue. That means, when binding a table to the Item[*] node and further down binding the repeating subform to the same, the table's body row fetches all Item[*] nodes and the product list stays empty.

If you really need to display content from the same repeating data node multiple times, you can only bind one of these lists or tables and need to create the other ones by script, without bindings. This will be a topic for a coming blog post. Stay tuned!

Filtering with Binding Expressions


We have just discussed that you cannot create two lists bound to the same repeating data node. However, there is a special case where this approach works: When you want to display different items in both lists and use binding paths with filter predicates.

Let's assume we have two different kinds of items in the data XML: Delivery Standard Items and Delivery Text Items, and for demonstration purposes we want to show them in separate lists or tables.

First of all, we have to find out how to differentiate between these two item types by looking at the XML data. In the sample above the Item node contains an element ItemTypeCode with the value 14. The element ItemTypeCodeName underneath tells us that the value 14 stands for Delivery Standard Item. If we wanted to show all Delivery Standard Items in the first list and everything else in the second list, we could adapt the binding path of the first list as follows:











Instead of: $.DeliveryNote.Item[*]
We could add a filter expression: $.DeliveryNote.Item.[ItemTypeCode == "14"]

The filter expression is added within the brackets instead of the *. Pay attention to the additional . in front of the brackets!

If you add this filter expression to the first list and your items have different ItemTypeCodes, the first list would only fetch elements with 14 and all remaining elements would be displayed in the second list.

IMPORTANT: You may only filter for elements that always appear with a value in the data model! If you would like to filter for an element that can be empty and is therefore omitted in the XML, the form generation would fail!

I will explain more details on that in the next blog about complex tables.

And that's it for the simple tables! In case you have questions, feel free to ask them in my live session:

Live Sessions (UPDATE 2024!)


As already mentioned at the beginning of this post, I’m delivering monthly live sessions with a changing agenda on the topic of print form adaptation. If you are interested and would like to join, here are some details:

Starting 2024 the live sessions have moved to a new platform: You can find them via this new direct link on learning.sap.com. You still need a corresponding subscription in order to register for the live session.

If you want to get informed about the next blogs of this series or updates on the live session, please follow this blog post by clicking on the green “follow” button on the left. You can also follow me fwys for more blog posts about SAP Customer Experience Solutions – Integration and Extensibility topics.