Skip to Content
Technical Articles

Virtual Context in SAP UI5

Hello Readers,

In this post, I am going to discuss about a scenario (and solution) that some of us might have faced while using smart forms in ui5 with CDS generated odata services.

Scenario:

Suppose we have a table in se11. The data from the table is brought to UI5 using CDS generated OData services. Now, in UI5 we need an smart form for creating an record for the same backend table, but the fields in the form should be smart.

The trick here is that, smart form in sap ui5 basically uses element binding, but when the data comes from back end it is the data of the whole table (for aggeration binding) as we have redefined get entityset to fetch the data. We cannot redefine get entity as it would throw a dump in case there are no records in the table (it is also not the standard way to bind an smart form).

The solution here is that once the odata is instantiated in a model variable in our controller, we can create an virtual entry in the model (an empty record with all the necessary properties), this gives us an context (Virtual Context). This context of the virtual entry/record (element), we can use to bind the smart form. Therefore, solving our problem of element binding.

We can keep updating the instance of the virtual entry as and when the user enters data in the form and once the user clicks on submit, we can send an update call to the backend with the id (primary key) of the virtual entry, thus making it the saved record by the user.

Lets look at an example below for the above scenario:

Consider the below user details table: (This is an example table with just 5 columns by me. This method works with any sap standard or custom table)

Now, the requirement in the UI5 side is to have an user creation form, which is a smart form, to be binded with the fields of this table. The smart form should look like below:

The advantages of using smart form here are that, if we use Hana CDS and Bopf from backend, then the validations, value helps and the fields can be properly managed from the backend itself, instead of manually adding the fields from the xml view in UI5 side.

Now, for the above table, when we generate the odata by redefining the get entity set method, the whole table data is sent to the UI5 side. Using this we would not be able to bind the smart form right away, because as mentioned earlier, using the standard methods, we need only one record from the table to get the structure of the fields required in the smart form and use this as element binding to bind to the smart form. So, as we cannot point to any record by hard coding we can use this concept of Virtual Context.

Code for smart form:

<smartForm:SmartForm id="idUserSmartForm">
<smartForm:Group>
				<smartForm:GroupElement>
					<smartField:SmartField value="{UserName}" />
				</smartForm:GroupElement>
				<smartForm:GroupElement>
					<smartField:SmartField value="{Department}" />
				</smartForm:GroupElement>
				<smartForm:GroupElement>
					<smartField:SmartField value="{Age}" />
				</smartForm:GroupElement>
</smartForm:Group>
<smartForm:Group>
<smartForm:GroupElement>
					<smartField:SmartField value="{EmailID}" />
				</smartForm:GroupElement>
</smartForm:Group>
</smartForm:SmartForm>

Code in Controller:

//In the controller's init function
onInit: function(){
         var oModel = this.getOwnerComponent().getModel();
	 //For creation of an virtual entry
         //create an entry of the user table collection with the specified properties and values
         var oPropertiesEntityObject = {
				UserName: "",
                                Age: "",
                                Department: "",
                                EmailID: ""
			};
         //Creation of an virtual element context
         var oContext = oModel.createEntry("/ZUser_Entity", {
				"groupId": "idUserGroup",
				properties: oPropertiesEntityObject ,
				success: function (oData) {
                                        //On success of creation of an context, return an unique user id 
                                        //generated from the backend. Store this id globally within the 
                                        //controller, to use it later on for updation/deletion.
					this.userID = oData.userID;
				}.bind(this)
			});
         //Final step, bind the context against the smart form (this can be done for views, dialogs  
         // as well).
         var oSmartForm = this.getView().byId("idUserForm");
         oSmartForm.setBindingContext(oContext);
}

 

Now, once the user finishes editing the form and clicks save, we can use the globally stored id to save the form. In case the user clicks on discard, we can delete the virtually created entry.

Note: In case, while creating an virtual context, you dont want any changes in the back end i.e. any record to be created or changed in the back end, you can set the default binding context of the model as one way explicitly before creating an virtual entry.

For more information and examples on this method, kindly refer to the links below:

https://github.com/SAP/openui5/issues/1447

https://answers.sap.com/questions/12349405/twoway-binding-with-createentry-sapui5.html

Please feel free to ask any doubts/question in comments.

 

Regards,

Arjun Biswas

 

 

3 Comments
You must be Logged on to comment or reply to a post.
  • Nice example!!

    One suggestion, you don’t need to pass empty values to the createEntry,

    var oPropertiesEntityObject = {
    				UserName: "",
                                    Age: "",
                                    Department: "",
                                    EmailID: ""
    			};

    it should work well without passing any empty values. You could use that to pass default values though.

    var oPropertiesEntityObject = { };

    Thanks,

    Mahesh