Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to use 2 models in one view

Tags:

sapui5

I am stuck on whether a concept is possible in SAPUI5, and as the docs can be a little hard to work with at this level of detail, I am asking this question earlier in my research path than normal. Mainly I don't want to spend too much time if there is an immediate 'No' answer.

I have a use case of a view that is master-detail, using a JSON model, but I have to produce my own controls - I can't use a SplitApp etc.

The model is effectively a 2-layer deep tree, master leading to detail. Conceptually like this:

{ 
    "master": [
        {
            "name": "Master 1",
            "detail" : [
                {
                "name": "Detail 1-1"
                },
                {
                "name": "Detail 1-2"
                }
            ]
        },
        {
            "name": "Master 2",
            "detail" : [
                {
                "name": "Detail 2-1"
                },
                {
                "name": "Detail 2-2"
                }
            ]
        }
    ]
}   

The UX is that there will be a selectable list of masters and when a selection is made the detail list control will be refreshed to show the details that are children of the selected master.

I am familiar with binding a model to the view via

sap.ui.getCore().setModel(oModel) 
this.getView().setModel(oModel)

but this binds all controls in the view to one model according to my learning to date.

The options I think may be worth pursuing are:

  1. Bind a separate model to each of the master and detail controls and write custom code to switch out the detail-model when a master is selected. But how to make such bindings;
  2. Use a single model but somehow set the detail control to recognise the 'current selected' master.
  3. Use some kind of filter on the detail control.

Explaining 2 further, if say I was using a table for the detail display I might have in the table def

   <Table
            id="detailList"
            items="{
                path: '/'
            }",
            ...
     >

So I would be looking to modify the path to something like

path: '/master[n]/detail/'

where n represents the selected master instance.

Is either possible, or is there another alternative, or should I give up.

EDIT: I found this potential filter-based solution by Michael Herzog here. His description is:

i'll give you an example, how you can implement a matser-detail relationship in SAPUI5.

Use case: When the user is clicking on a client in the first table, all related orders should be displayed in the second table. Orders from other clients should be hidden.

So, in our view, we have two tables:

  1. Table: Clients

  2. Table: Orders

After you created both tables and set up the databinding, implement this eventhandler on the first table:

oTableClients.attachRowSelectionChange( function(oEvent){

    // first, we fetch the binding context of the selected row
     var selectedRowContext = oEvent.getParameter("rowContext");
     // get the ID of the customer via rowContext. The model-object represents the data of the first table
     var selectedClientId = oModel,getProperty("id", selectedRowContext);
     // get binding of second table
     var ordersBinding = oTableOrders.getBinding();
     //create new filter to show the relevant data for the selected customer
     var oFilter = new sap.ui.model.Filter("clientId", sap.ui.model.FilterOperation.EQ, selectedClientId);
     // apply filter to binding
     ordersBinding.filter([oFilter]);
});

I can see that this approach is viable for me - is there any reason why this pattern is fundamentally flawed?

like image 964
Vanquished Wombat Avatar asked Jan 19 '17 23:01

Vanquished Wombat


1 Answers

In general your view can have as much models you like. The only restriction is that there can be only one nameless model, i.e. all other models need to be named. The following code shows the difference:

this.getView().setModel(new JSONModel(data));
this.getView().setModel(new JSONModel(data), name));

To bind against a named model you have to provide its name in the binding instruction, otherwise the runtime uses the nameless model. The following example shows the difference (note that you can use the short binding syntax unless you want to provide additional parameters, i.e. you can omit the path attribute:

<Table items="{/path}">
<Table items="{name>/path}">

In your example I would suggest to work with one model and use the binding context to control the data shown in the detail table.

The binding of the details table should be relative and look as follows:

<Table id="detailList" items="{detail}">

The handler for handling selection of a master list as follows:

onMasterItemSelect : function(event) {
    // get the binding context of the currently selected master item, e.g. /master/0
    var masterBindingContext = event.getParameter("listItem").getBindingContext();

    // bind detail table to the selected master item using bindElement
    this.byId("details").bindElement(masterBindingContext.getPath());
}
like image 121
matbtt Avatar answered Sep 22 '22 09:09

matbtt