Dynamic field control using Annotations in SAPUI5
Introduction
Fiori Elements are becoming increasingly popular. They provide a framework to generate SAPUI5 apps at runtime based on metadata annotations.
Instead of generating a whole application, developers can also use Smart Controls for their existing apps, to add tables, forms, etc. in a fast way. These controls use annotations that add semantics and structures to the data, provided by the user.
In this example I want to illustrate the field control annotation in order to change the state of certain input fields dynamically.
The first screen of our demo app shows a table (SmartTable) with a list of customers. By selecting a customer, there will be a navigation to the detail page, where customer data can be edited in a form (SmartForm).
Annotations and Smart Controls
The Entity-Type Customer within our metadata.xml file comes with an Id and a Customername.
<EntityType Name="Customer" sap:content-version="1">
<Key>
<PropertyRef Name="Id"/>
</Key>
<Property Name="Id" Type="Edm.String" Nullable="false" MaxLength="10" sap:label="Customer ID" sap:creatable="false" sap:updatable="false"/>
<Property Name="Customername" Type="Edm.String" Nullable="false" MaxLength="40" sap:label="Customer" sap:creatable="true" sap:updatable="true"/>
</EntityType>
We use SmartFields for displaying the values. This control can be used as standalone, for example in XML views:
<smartField:SmartField value="{Id}" id="id"/>
<smartField:SmartField value="{Customername}" id="customer"/>
…in combination with a SmartTable (our first screen):
<smartTable:SmartTable id="smartTable" entitySet="Customers"
initiallyVisibleFields="Id,Customername"
customData:useSmartField="true">
...
</smartTable:SmartTable>
…or with a SmartForm (our detail page):
<smartForm:SmartForm id="smartForm" entityType="Customer">
<smartForm:Group label="Customer Details" id="detailGroup">
<smartForm:GroupElement id="idGroupElement">
<smartField:SmartField value="{Id}" id="id"/>
</smartForm:GroupElement>
<smartForm:GroupElement id="customerGroupElement">
<smartField:SmartField value="{Customername}" id="customer"/>
</smartForm:GroupElement>
</smartForm:Group>
...
</smartForm:SmartForm>
If the SmartForm or SmartTable control is in “editmode”, Id is still readonly, whereas Customername can be edited, due to the appropriate annotation within metadata.xml file ( sap:creatable=”true” sap:updatable=”true”).
Dynamic Field Control
So far, so easy!
However… as these annotations are static, in certain cases it might be necessary to provide a dynamic functionality for some fields.
For example: Some customers should have a Street and a City field as well. For others, these two values should even be updatable. It is impossible to express this up-front via metadata annotations.
In that case, the annotation sap:field-control can help!
We adjust the metadata.xml:
<EntityType Name="Customer" sap:content-version="1">
<Key>
<PropertyRef Name="Id"/>
</Key>
<Property Name="Id" Type="Edm.String" Nullable="false" MaxLength="10" sap:label="Customer ID" sap:creatable="false" sap:updatable="false"/>
<Property Name="Customername" Type="Edm.String" Nullable="false" MaxLength="40" sap:label="Customer" sap:creatable="true" sap:updatable="true"/>
<Property Name="Street" Type="Edm.String" Nullable="true" MaxLength="30" sap:label="Street" sap:field-control="UX_FC_Address"/>
<Property Name="City" Type="Edm.String" Nullable="true" MaxLength="30" sap:label="City" sap:field-control="UX_FC_Address"/>
<Property Name="UX_FC_Address" Type="Byte"/>
</EntityType>
We’ve added a new property UX_FC_Adress to the Entitytype Customer. Furthermore, we need the properties Street and City. Each of them has an additional Attribute: sap:field-control=”UX_FC_Address”.
<Property Name=”Street” Type=”Edm.String” Nullable=”true” MaxLength=”30″ sap:label=”Street” sap:field-control=”UX_FC_Address”/>
<Property Name=”City” Type=”Edm.String” Nullable=”true” MaxLength=”30″ sap:label=”City” sap:field-control=”UX_FC_Address”/>
The value of the UX_FC_Adress property defines, if these new fields are hidden(value = 0), read-only(value = 1), optional(value = 3) or mandatory(value = 7).
Within our backend there should be an appropriate logic, to set the value of UX_FC_Address for each customer. As our application is running with mockdata, we are using the following json-file to illustrate the different data for each Customer:
[
{"Id": "1", "Customername": "CustomerA", "Street": "StreetA", "City": "CityA", "UX_FC_Address": 0 },
{"Id": "2", "Customername": "CustomerB", "Street": "StreetB", "City": "CityB", "UX_FC_Address": 1 },
{"Id": "3", "Customername": "CustomerC", "Street": "StreetC", "City": "CityC", "UX_FC_Address": 3 },
{"Id": "4", "Customername": "CustomerD", "Street": "StreetD", "City": "CityD", "UX_FC_Address": 7 }
]
In the last step we have to add our new fields to our SmartForm:
<smartForm:Group label="Customer Details" id="detailGroup">
<smartForm:GroupElement id="idGroupElement">
<smartField:SmartField value="{Id}" id="id"/>
</smartForm:GroupElement>
<smartForm:GroupElement id="customerGroupElement">
<smartField:SmartField value="{Customername}" id="customer"/>
</smartForm:GroupElement>
</smartForm:Group>
<smartForm:Group label="Address" id="addressGroup">
<smartForm:GroupElement id="streetGroupElement">
<smartField:SmartField value="{Street}" id="street"/>
</smartForm:GroupElement>
<smartForm:GroupElement id="cityGroupElement">
<smartField:SmartField value="{City}" id="city"/>
</smartForm:GroupElement>
</smartForm:Group>
By running the application, we can see that CustomerB, CustomerC and CustomerD have additional values Street and City. However, these values are invisible for CustomerA.
Our SmartForm behaves also different, based on the selected Customer: For CustomerB, only the Customername is editable:
…for CustomerD the values Street and City are shown as mandatory input fields in our form:
Conclusion
Using the field-control Annotation is an easy way to dynamically change the behavior of the UI without additional UI5 coding. The SmartControl is a wrapper for other controls. It interprets OData metadata to determine the control that has to be instantiated. The OData entity is derived from the control’s binding context.
Thanks for detailed blog.
Hi,
Will Smart Forms will update automatically ?
In my project we are using smartForms and Smart Tables. At first time, When user select a row in the table, an odata batch call is happening to the backend for the smartForm entity. After some time When I select the same entry in the table , the OData call is not happening for the smart form entity.
Hi,
Will Smart Forms update automatically ?
In my project we are using smartForms and Smart Tables. At first time, When user select a row in the table, an odata batch call is happening to the backend for the smartForm entity. After some time When I select the same entry in the table , the OData call is not happening for the smart form entity.
Hi Karthik,
yes indeed, if you do not change anything on your data, there is no additional backend call again, as this entity is already part of your your "local" model.
Hi Maximilian,
I've tried to use the field-control in a SAP Fiori Elements application that I've created using the SAP Web IDE Full Stack List Report Application template. But here the following issue occurs:
The initial request to fill the list is based on my backend annotations and doesn't include the field-control attribute. Due to this fact the columns annotated with field-control and the attribute are still shown as before. But even if I personalize the table and make the field-control attribute visible nothing changes.
Do you have any tip how to make use of field-control with Fiori Elements?
Best regards
Gregor
Hi Gregor,
when it comes to extending Fiori Elements applications, this blog post might help you:
https://blogs.sap.com/2017/03/02/annotating-and-extending-fiori-element-applications/
On Part 2, you can also find an example about using field control:
https://blogs.sap.com/2017/03/02/annotating-and-extending-fiori-element-applications-list-report-part-2/
Best,
Maximilian
Hello Maximilian Rupp
I have added few custom fields using “Custom Fields and Logic” App and automatically in the MetaData , sap:field-control has been created for that Custom Field.
When I am trying to manipulate visibility in DPC_EXT class , Custom Field properties are not getting changed. I debugged alot and find out ,It is happening because of field - ROLE_SUFFIX of table - CFD_L_DEL_CDS .
I would like to understand what's the significance of this field? How to populate this field .
Hi Maximilian,
I'm trying to use the method you describe with Fiori Elements but the issue is that the Nullable property and the field-control annotation don't work the same way.
Using the field-control annotation, the field in the UI is shown as mandatory but there's no validation in the client app so an empty value can be sent to the backend. Using the Nullable="false" property, the input is validated in the client app before the request is sent to the backend.
Is there any way to validate the data before sending the request to the backend using field-control?
Cheers,
Pierre
Hi is it possible to implement smartFields without using Annotations?