Data Binding with Repeating Items and Simple Tables in Print Forms
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:
- How to get XML data for local preview of print forms without output history
- Data Binding Basics in Print Forms
- Data Binding with Repeating Items and Simple Tables in Print Forms (this blog)
- Data Binding with Repeating Items and Complex Tables in Print Forms
- Building Tables with Scripts
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:
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:
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.
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:
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:
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:
Bind Once Limitation
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:
|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:
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:
The live session is available on SAP Learning Hub. You need a subscription with access to the SAP Customer Experience learning resources in order to register for the live session.
There are two ways to access to the registration page of the live session (as well as the schedule of the next occurrences):
- You can use the following direct link, but please remember you need to be logged in on SAP Learning Hub first to use the link!
Direct link: Live Sessions – SAP Customer Experience: C4C Extensibility
- Alternatively you can go to SAP Learning Hub, and search for “Print Form Adaptation with Adobe LiveCycle Designer”. Look for a webinar with the headline “Live Sessions – SAP Customer Experience: C4C Extensibility” and the code: (LS_CX_C4CEXT_EN / EXPERT_LED) under “Learning Content”
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 Felix Wyskocil for more blog posts about SAP Customer Experience Solutions – Integration and Extensibility topics.