Hello Community!
In this blog, I’ll try to show my approach to solve an issue with oData and Dynamic Items and how to manipulate that data.
The Issue
Based on the Floorplan selected (ObjectPage, Dynamic Page, etc), we can confront the problem of the data binding with dynamic items (e.g. List items). More precisly if we don’t know the ids for these new elements to manipulate the values in future operations.
Helpful links
If you need some introduction to this kind of Floorplan in particular, check the following links (very helpful and really apreciate the help received by the authors) :
Fiori elements – How to Develop an Object Page
SAP Fiori Scenario
In my case I choose to develop an Object Page from the scratch to obtain a simple app to make operations with the values in input fields. I create dynamic facets and items.
a simple idea of the Object Page XML
<ObjectPageSection
title="{mainOdataModel>MenuDescr}"
subSections="{ path: 'mainOdataModel>Nav_MenuHdr_To_MenuItem', templateShareable: true }">
<subSections templateShareable="true">
<ObjectPageSubSection title="{mainOdataModel>ItmDescr}">
<l:VerticalLayout id="containerLayout" width="100%">
<l:BlockLayout>
<l:BlockLayoutRow>
<l:BlockLayoutCell width="1">
<m:FlexBox height="60px" justifyContent="Center" alignItems="Center">
<m:Avatar backgroundColor="Random" displaySize="S" src="sap-icon://picture"/>
</m:FlexBox>
</l:BlockLayoutCell>
<l:BlockLayoutCell width="12">
<m:FlexBox height="60px" justifyContent="Start" alignItems="Center">
<m:Label text="{mainOdataModel>MenuIngredient}"/>
</m:FlexBox>
</l:BlockLayoutCell>
<l:BlockLayoutCell width="2">
<m:FlexBox height="60px" justifyContent="Center" alignItems="Center">
<m:StepInput
change="onInputChange( $event, ${mainOdataModel>ItemId}
description="{mainOdataModel>ItmUnitPrice} {mainOdataModel>ItmCurr} / {i18n>Unit}"
editable="true"
min="0"
value="0"/>
</m:FlexBox>
</l:BlockLayoutCell>
</l:BlockLayoutRow>
</l:BlockLayout>
</l:VerticalLayout>
</ObjectPageSubSection>
</subSections>
</ObjectPageSection>
Explanation
Imagine you want to display the info on your table, you must set the entity bind and the magic is done.
<Table items="{
path : '/YourEntityList',
parameters : {
... // in case you need to set some parameters or filters check the SAP documentation
}}">
...
<items>
<ColumnListItem>
<cells>
<Text text="{YourItemDescription}"/>
</cells>
</ColumnListItem>
</items>
</Table>
But what happens if we need to create rows for every item and inside our new rows, we must set input fields and to be more creatives, we need to do operations with the input field values after the page is rendered and then we must save that data.
Well, good practices says that you must work with the ids of the particular elements that you need and we are completly agree with that … WAIT a minute! my new items doesn’t have ids
that's not true! if you investigate a little bit on your browser you will find something like this
<div id="__section0-__section1-application-Test-url-component---App--idObjectPageLayout-0-5" ...>
OK, but I want to set my propper ids to identify and manipulate them and their values, so we can properlly think in set the ids dynamically with our oData as follows id=”{myOdataModel>ItemId}”
Well sorry but for the moment that’s not possible and you will confront error in your View.
Possible Solution
My solution approach, if you want to continue with your XML View, is to send the info from the view to your controller.
When we trigger the event to add a new unit we can send all the info on the event itself.
~~ View ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<m:StepInput change="onInputChange"
description="{ItmDescription}"
editable="true"
min="0"
value="0"/>
~~ Controller ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
onInputChange: function(oEvent){
var inputField = oEvent.getSource();
var inputValue = parseFloat(inputField.getProperty("value"));
//... put some more code lines to implement what you want
}
but I need to manipulate different items at the same time and work with the Entity data.
I neet to pass the data from View to Controller to manipulate it, a way to do that is to know the ID in the Controller but this approach is not applicable because is dynamic !
So my approach is to send the info to the controller and work with it in an array or object or what ever you need already created previously to save and manipulate that info.
~~ View ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// We send our info
change = onInputChange( $oEvent, ${myOdataModel>ItemDescription}, ${myOdataModel>MyItemId}, ${myOdataModel>MyItemPrice} )
~~ Controller ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// In this case we will work with an array of objects
myArray: [],
...
var myArrayModel = new sap.ui.model.json.JSONModel();
myArrayModel.setData(this.myArray);
...
// trigger the input event
onInputChange: function(oEvent, ItemDescription, MyItemId, MyItemPrice){
var oInputField = oEvent.getSource();
var inputValue = parseFloat(oInputField.getProperty("value"));
var unitPriceFloat = parseFloat(MyItemPrice);
// In our array of objects we can set a property as ID in case we need later for any other reason
var tempIndex = MyItemId;
// we set the index to check if this object exist, now we can push a new object or update a previous one
var objIndex = this.myArray.findIndex((obj => obj.index === tempIndex));
if(objIndex === -1){
this.myArray.push({index:tempIndex, ItmQty: inputValue, ItmPrice: unitPriceFloat});
} else {
this.myArray[objIndex].ItmQty = inputValue;
}
// Now call your method to get the operations done with the info setted on our Array
// and return the final value on the Total field
this.getView().byId("idTotalInputField").setValue(this.getTotalValue(this.myArray));
},
...
// Example of manipulation data:
// we calculate a total with the price and quantity of every selected item on the array.
getTotalValue: function(aSubTotals){
var total = 0;
$.each(aSubTotals, function () {
var subTotalItem = this.ItmQty * this.ItmPrice;
total += subTotalItem;
});
return total;
}
Conclusion
The experience with SAP Fiori Element is good but you will not find a standard solution for every case.
In this scenario I choose to use the communication between View and Controller with this pattern ${myOdataModel>myItemId} due we haven’t a propper way to identify all the input fields to solve the calculations.
Original Article:
https://blogs.sap.com/2020/03/13/how-to-work-with-dynamic-items-on-fiori-objectpage-floorplan/