How to Bind OData $count from expanded collection in an XML view

后端 未结 4 601
终归单人心
终归单人心 2020-12-30 05:30

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

相关标签:
4条回答
  • 2020-12-30 06:01

    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:

    View

    1. Use a controller
    2. Give your list an ID
    3. Use a function on list's updateFinished event.
    <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>
    

    Controller

    1. Implement countProducts function
    2. Use jQuery to request the $count for each list item - Notice how the URL is generated concatenating model's service URL with the item's binding context
    3. As jQuery uses asynchronous requests, by the time you get the first response, your for will be finished. So it can use IIFE to avoid filling just the last list item with your AJAX response
    countProducts: 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);
      }
    }
    
    0 讨论(0)
  • 2020-12-30 06:04

    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>
    
    0 讨论(0)
  • 2020-12-30 06:09

    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.

    0 讨论(0)
  • 2020-12-30 06:18

    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"
    
    0 讨论(0)
提交回复
热议问题