0
votes

I read the data from an OData V2 service at the startup of my SAPUI5 application with oModel.read(). The data are correctly loaded from the backend into the ODataModel. Later I would like to use one of my entities in a fragment (value help).

As the control to display the data in the fragment is a sap.m.Tree control. I can not use a local JSONModel to bind the data to the fragment but have to stick to the ODataModel.

How has the binding to be done to get data displayed in my fragment?

Here is the oModel.read:

oModel.read("/CategoriesSet", {
  filters: aFilters,
  success: function(oResult) {
    // ...
  },
});

In the Value Help, the fragment is called:

onCatValueHelp: function(oEvent){
  if (!this._oDialog) {
    this._oDialog = sap.ui.xmlfragment("<XXXXX>.view.Categories", this);
    this.getView().addDependent(this._oDialog);
  }
  this._oDialog.open();
},

And this is the Fragment:

<Tree id="CatTree" mode="MultiSelect"
  items="{
    path: '?????',
    parameters: {
      countMode: 'Inline',
      operationMode: 'Client',
      numberOfExpandedLevels: 0
    }
  }">
  <StandardTreeItem title="{CatName}" tooltip="{CatID}" />
</Tree>

If I use '/CategoriesSet' for the path, then I get the data loaded into the fragment, but the data is then fetched from the backend again, but without the filter. And as the backend call is not very performant, I would rather use the data that is already existing in the model from the previous oModel.read().

2
The issue is deeper as you'd like to avoid retrieving all CategoriesSet entities. But with operationMode: 'Client', all entities are fetched first and then the filters will be applied on the client even if the filters are defined in the tree binding constructor. According to the doc: > If OperationMode.Client is used, the complete collection without filters is requested; filters are applied on the client side.Boghyon Hoffmann
Does your backend support > pre-filtering the tree and [...] responding with a complete tree hierarchy, including all inner nodes? Then you could add useServersideApplicationFilters: true to the parameters (but without operationMode: 'Client'!) in order to avoid fetching all entities. Only then the $filter query will be added to the request URL the API reference.Boghyon Hoffmann
(Personal opinion..) I'd reconsider whether displaying the categories in a tree is absolutely required. It can become quickly too complex for both frontend and backend devs to implement the requirement.Boghyon Hoffmann

2 Answers

1
votes

As shown in this answer, you can preliminarily define static filters in XML.

If the filter values, however, need to be dynamically determined, you'll have to create the filter instances in JS and pass them to the tree binding. You can keep the binding definition in XML but the aggregation binding should be suspended: true first (in order to avoid sending multiple requests unnecessarily).

<Tree id="CatTree" items="{
  path: '/CategoriesSet',
  ...,
  suspended: true
}">
  <StandardTreeItem title="{CatName}" tooltip="{CatID}" />
</Tree>
// As soon as the Tree is accessible from JS:
const suspendedTreeBinding = myTree.getBinding("items");
suspendedTreeBinding.filter(aFilters, "Application");
suspendedTreeBinding.resume(); // starts sending a single data request but with the filter

There is no need to call oModel.read() beforehand.


Off-topic but try to avoid using the old factory function sap.ui.xmlfragment if possible as it's deprecated since UI5 v1.58! Use sap/ui/core/Fragment.load instead. E.g. like this.

0
votes

If you want to perform the read at the beginning, you can store the result of the success callback in a JSONModel and then bind this model to the Fragment.

Alternatively, you can skip the first call and configure carefully the call in the Fragment to match your needs.

Actually this is exactly how odata models work.

Personally, I prefer the first option because filtering is easier in javascript than in a declarative approach.