May be this is a basic question, but I have trouble binding the OData count in XML view.
In the following example, I want to bind the count of products from the ODat
Well.. I had exactly the same requirement and didn't want to perform the clever solution from @jasper as it will load all Products collection from the oData service.
This was the way I solve it:
<mvc:View
controllerName="view.Root"
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
>
<List id="list"
headerText="Categories"
items="{/Categories}"
growing="true"
growingThreshold="4"
growingScrollToLoad="true"
updateFinished=".countProducts"
>
<ObjectListItem
title="{description}"
numberUnit="Products"
/>
</List>
</mvc:View>
countProducts
functionfor
will be finished. So it can use IIFE to avoid filling just the last list item with your AJAX responsecountProducts: function(e){
var m = sap.ui.getCore().getModel();
var items = this.byId("list").getItems();
for (var item_index = 0; item_index < items.length; item_index++) {
var item = items[item_index];
(function(_item) {
$.get(
m.sServiceUrl + _item.getBindingContextPath() + "/Categorias/$count",
function(count) {
_item.setNumber(count);
}
);
})(item);
}
}
I dont think its currently possible - $count is an OData query option, the equivalent in ODataListBinding is length, eg Products.length I cant think of a way to bind to it
you can achieve the count in a couple of ways using a formatter
option 1 - the simplest, create a list binding which reads the total number of products, it does a synchronous call and returns only the $count
function productCount(oValue) {
//return the number of products linked to Category // sync call only to get $count
if (oValue) {
var sPath = this.getBindingContext().getPath() + '/Products';
var oBindings = this.getModel().bindList(sPath);
return oBindings.getLength();
}
};
<List items="{/Categories}"} >
<ObjectListItem
title="{CategoryName}"
number="{path : 'CategoryName',formatter:'productCount'}"
numberUnit="Products"
</ObjectListItem>
</List>
option 2 - use an expand and return a very small set of data, in this case only CategoryName and ProductID, the caveat here is whether you have to by pass table paging to get full list
function productCount(oValue) {
//read the number of products returned
if (oValue) {
return oValue.length;
}
};
<List items="{/Categories,parameters:{expand:'Products', select:'CategoryName,Products/ProductID'}}">
<ObjectListItem
title="{CategoryName}"
number="{path : 'Products',formatter:'productCount'}"
numberUnit="Products"
</ObjectListItem>
</List>
I had a similar issue. Although I am not thrilled with my solution, it uses expression binding and works without the need for a separate formatter:
<List items="{/Categories}"} >
<ObjectListItem
title="{CategoryName}"
number="{= ${Products}.length }"
numberUnit="Products" />
</List>
Like @Jasper_07, you still need to include Products
in the expand, but you are ignoring most of the data coming back.
I´d another solution using Manifest.json, Component.js and Controller.js for similar Issue.
First, I defined the Id in App.view.xml, for example:
<Title id="titleId" text="" level="H2"/>
After, I check Manifest.json, in especial:
{
"sap.app": {
"dataSources": {
"AXXX": {
"uri": "https://cors-anywhere.herokuapp.com/https://services.odata.org/Northwind/Northwind.svc/",
Next, in Componente.js at init:function() I put:
var oDataServiceUrl = this.getMetadata().getManifestEntry("sap.app").dataSources["AXXX"].uri;
console.log("oDataServiceUrl = ", oDataServiceUrl);
localStorage.setItem('oDataServiceUrl', oDataServiceUrl);
This code read Manifest.json and get Url to oDataService called AXXX.
Finnaly, I created one function in App Controller, such as:
countCustomersInAXXX : function (oEvent) {
var suffix = 'Customers/$count';
var oDataServiceUrl = localStorage.getItem('oDataServiceUrl');
var oDataServiceUri = oDataServiceUrl.concat(suffix);
console.log('App.controller.js: oDataServiceUri', oDataServiceUri);
var count = $.ajax({type: "GET", url: oDataServiceUri, async: false}).responseText;
console.log('App.controller.js: countCustomersInAXXX:' , count);
this.getView().byId("titleId").setText(count);
}
This code get the quantity of Customers and set the value in titleId.
To start this process you can user a button or one event, in my case I use this Table property:
updateFinished="countCustomersInAXXX"