OData binding with $expand

ykay picture ykay · May 28, 2015 · Viewed 19.1k times · Source

We have to bind a OData url to UI5's ODataModel

https://sapes1.sapdevcenter.com/sap/opu/odata/sap/ZCD204_EPM_DEMO_SRV/BusinessPartners('0100000000')/SalesOrders/?$expand=SalesOrderItems

We are able to bind root level items that belong to each SalesOrder. However, we are running into problem in case of binding data from SalesOrderItems which are a child to SalesOrder.

We are not able to bind SalesOrderItems' fields to any of our objects. We tried using {SalesOrderItems/results/QuantityUnit}, {SalesOrderItems/QuantityUnit} without much luck.

Can you please suggest any alternatives?

There is 1..m cardinality between SalesOrder and SalesOrderItem

// model of oData

var model = sap.ui.model.odata.ODataModel("proxy/https/sapes1.sapdevcenter.com/sap/opu/odata/sap/ZCD204_EPM_DEMO_SRV/",true,'username','password');
//app is defined in index.html here we are setting model to the app.

App.setModel(model);

// create a table

var pastOrder_S3= new sap.m.Table("PastOrder_S3",{
            inset:true,
            //visibleRowCount: 2,
            firstVisibleRow: 2,
            fixedColumnCount: 2,
            columns:[
                     new sap.m.Column({
                         header:new sap.m.Label("item").setText("Items"),
                         hAlign:"Left",
                         width:"20px",
                         demandPopin:true,
                         popinDisplay:"Block",
                         minScreenWidth: sap.m.ScreenSize.Medium
                     }),
                     new sap.m.Column({
                         header:new sap.m.Label("orderdetail").setText("OrderDetails"),
                         hAlign:"Left",
                         width:"200px",
                         demandPopin:true,
                         popinDisplay:"Block",
                         minScreenWidth: sap.m.ScreenSize.Medium
                     })
});

//create a template to bind into the table using model.

var oTemplate_S3= new sap.m.ColumnListItem({
        type: sap.m.ListType.Active,
        cells: [

        new sap.m.Text({
        text:"{ProductName} \n {ProductID}"
                }),    

           new sap.m.Text({
                text:"OrderId: {SalesOrderID} \n {DeliveryDate} \n {TotalSum}{Currency}"
                })             
             ]
    });

// bind into the table.
`pastOrder_S3.bindAggregation("items","BusinessPartners('BusinessPartnerId')/SalesOrders/?$expand=SalesOrderItems",oTemplate_S3);`

Here we have a child property named 'SalesOrderItems' we need to read the properties inside the salesorderitems.

Answer

Serban Petrescu picture Serban Petrescu · Apr 23, 2017

When binding the aggregation to an OData collection, the expand parameter (and any other parameters for that matter) has to be given separately, not part of the collection URI.

In an nutshell, you will have to do the following:

oTable.bindAggregation("items", {
    path: "/BusinessPartners('BusinessPartnerId')/SalesOrders",
    template: oTemplate,
    parameters: {
       expand: "SalesOrderItems"
    }
});

Check out the bindAggregation and the ODataListBinding constructor documentation for more details.

Another problem that you will face is that you have this 1:n cardinality between the SaleOrder and the SaleOrderItems. This means that you will only be able to use this navigation property to bind an aggregation and not directly a property (so you need to have something like a table inside another table).

You will have to clearly define what should be displayed from the SaleOrderItems to be able to 'flatten' it (e.g. do an aggregation, or pick the first one, etc). This will most likely imply that changes must be made in the OData service or you will have to use either a custom control in UI5 or a JSONModel instead of / together with the OData one.