Skip to Content
Technical Articles
Author's profile photo Soumya Mishra

Implement pagination using sap.m.Table and JSONModel

 

We were trying to implement pagination, in the sap.m.Table control. The issue was that we were not using OData and that is why the functionality was not available to us out of the box. We had binded our table with a JSONModel.

So you must be thinking what was the challenge in that? Our main challenge was that the model we were using – JSONModel , is actually a client side model. It does not support server side pagination. We came across this in the ui5 documentation: ““The JSON model is a client-side model and, therefore, intended for small data sets, which are completely available on the client. The JSON model does not support mechanisms for server-based paging or loading of deltas. ” Still confused? Read this .

Our second challenge was that the sap.m.Table supports pagination out of the box but only with Odata service.

There were a number of solutions available on the web suggesting to extensively extend the JSONModel which means rewriting a lot of inbuilt functions. We realized trying this out that the more we extend the inbuilt functions, the deeper pit we are digging for ourself. So here’s the approach we came up with –

  • Extend the JSONModel : Instead of overwriting several inbuilt functions we ended up overwriting one function : getLength. In order for the “Load More” option to come up, the table internally checks if the model binded to the table has more data than the number of rows currently shown. To get this, getLength function is called, which is overridden by us
  • Hook into the growingStarted event Once we have the “Load More” button, we can hook into the event growingStarted (which is triggered when you click on the “Load More” button) and make a REST call to the backend to actually get more data from the server.

Here’s how you can implement the above solution :

Step1: Extend sap.ui.model.JSONListBinding

In order to write the implementation of getLength we will be extending sap.ui.model.JSONListBinding. (You should create a js file say, PagingJSONListBinding.js and write the below code in it)

 

sap.ui.define([
 "sap/ui/model/json/JSONListBinding"
], function (
 JSONListBinding
 ) {
 "use strict";
/**
* PagingJSONListBinding
* @class
* @extends sap.ui.model.json.JSONListBinding
*/
 return JSONListBinding.extend("sap.di.mldm.model.PagingJSONListBinding", {
    constructor: function (oModel, sPath, oContext, aSorters, aFilters, mParameters) {
    JSONListBinding.apply(this, arguments);
    },
    getLength: function() {
    let count = this.getModel().oData.count; //assuming model has 'count'
    return this.getModel().getProperty("/" + count);
 }
});
});

 

Step 2: Extend sap.ui.model.json.JSONModel

Extend sap.ui.model.json.JSONModel and override bindList to return an object of your extended class PagingJSONListBinding. (Create another js file say PagingJSONModel.js and write the below code in it)

sap.ui.define([
"<your-namespace>/PagingJSONListBinding",
"sap/ui/model/json/JSONModel"
], function (
  PagingListBinding,
  JSONModel]
  ) {
  "use strict";
  /**
  * PagingJSONModel

  *@class
  * @extends sap.ui.model.json.JSONModel
  */
  return JSONModel.extend("<your-namespace>.PagingJSONModel", {
    constructor: function(oRestClient) {
      JSONModel.apply(this, arguments );
    },
    bindList: function(sPath, oContext, aSorters, aFilters, mParameters) {
    return new PagingListBinding(this, sPath, oContext, aSorters, aFilters,
      mParameters);
    }
 });
});

 

Step 3: Implement growingStarted event

Write a function for the growingStarted event of sap.m.Table to make an API call to get more data.

 

 

Sample

Table.view.xml

<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns:core="sap.ui.core"
xmlns="sap.m" controllerName="<your-namespace>.Table" >
	<Page showHeader="false" backgroundDesign="Solid" id="app">
		<content>
			<Table id="table" items="{ path: 'Model>/array' }"
				growing="true" growingThreshold="20"
				growingStarted="onGrowingStarted">
				<columns>
					<Column>
						<Text text="{i18n>heading1}"/>
					</Column>
					<Column>
						<Text text="{i18n>heading2}"/>
					</Column>
				</columns>
				<items>
					<ColumnListItem>
						<cells>
							<Label text="{Model>property1}"/>
							<Text text="{Model>property2}" />
						</cells>
					</ColumnListItem>
				</items>
			</Table>
		</content>
	</Page>
</mvc:View>

 

Table.controller.js

sap.ui.define([
  "<your-namespace>/BaseController",
  "sap/ui/model/json/JSONModel"
  ], function (BaseController, JSONModel) {
  "use strict";
  return BaseController.extend("sap.di.mldm.controller.table", {
    onGrowingStarted: function () {
    //API calls to fetch more data
    }
  }
});

 

PagingJSONListBinding.js

sap.ui.define([
  "sap/ui/model/json/JSONListBinding"
 ], function (
    JSONListBinding
    ) {
    "use strict";
  /**
   * PagingJSONListBinding
   * @class
   * @extends sap.ui.model.json.JSONListBinding
   */
    return JSONListBinding.extend("sap.di.mldm.model.PagingJSONListBinding", {
      constructor: function (oModel, sPath, oContext, aSorters, aFilters, mParameters) {
      JSONListBinding.apply(this, arguments);
    },
    getLength: function() {
    var count = this.getModel().oData.count; //assuming model has 'count'
    return this.getModel().getProperty("/" + count);
  }
});
});

 

PagingJSONModel.js

sap.ui.define([
  "<your-namespace>/PagingJSONListBinding",
  "sap/ui/model/json/JSONModel"
  ], function (
  PagingListBinding,
  JSONModel]
  ) {
  "use strict";
    /**
    * PagingJSONModel
    * @class
    * @extends sap.ui.model.json.JSONModel
    */
    return JSONModel.extend("<your-namespace>.PagingJSONModel", {
      constructor: function(oRestClient) {
      JSONModel.apply(this, arguments );
      },
      bindList: function(sPath, oContext, aSorters, aFilters, mParameters) {
      return new PagingListBinding(this, sPath, oContext, aSorters, aFilters,
      mParameters);
      }
  });
});

 

Therefore, we see that sap.m.Table does not provide out of the box support for pagination using JSON Model but we can easily achieve pagination by extending the JSONModel and hooking into the growingStarted method once load more is clicked.

 

Happy learning!!

 

Assigned Tags

      6 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Shai Sinai
      Shai Sinai

      Hi,

      As far as I know, growing does work out-of-the-box also for JSON model.

      What was the exact technical issue?

      Author's profile photo Raza Hassan
      Raza Hassan

      Hi,

      Nice effort to find a solution on your own to deliver the requested functionality but the title of this blog is a little misleading.

      This is not a pagination feature you are talking about. Pagination is when you have the capability of clicking on any page number like you have a rage from 1 to 10 pages and you want to directly jump to page 5 items.

      The feature you have implemented and are talking about is a lazy loading - growing list - delta tokening, etc.

      Author's profile photo Pieter Janssens
      Pieter Janssens

      Hi,

      Thanks for sharing. I would also suggest to change your title/content to use 'growing' instead of 'pagination'.

      Based on your example, I have implemented a POC using a factory function.

      Best regards,

      Pieter

       

      Author's profile photo Martin Ceronio
      Martin Ceronio

      Hi Soumya,

      Thanks for this article.

      It's a great starting point, though I agree with the other comments that perhaps the title should talk about "growing" rather than "pagination" and maybe it would be nice to show your solution more comprehensively.

      In your solution, how are you returning the count? You seem to have a property in your extended ListBinding whose name is stored in the "count" property of the model, is that correct?

      In Pieter Janssens example implementation, he just returns the value directly from the model, though I wonder if there is a neater, or more idiomatic way of doing this.

      But I should add that this has helped me get to a working solution, so thank you very much!

      Thanks and Regards,

      Martin

      Author's profile photo Boghyon Hoffmann
      Boghyon Hoffmann

      Please keep in mind that UI5 doesn't actually support extending existing model implementations (JSONModel, ODataModel)

      "The subclassing of standard models is not supported in SAPUI5."

      Extending JSONModel might break the application in the future.

      Author's profile photo Octav Onu
      Octav Onu

      Hello,

      I have achieved the same functionality by manipulating the iLength variable of the corresponding binding.

      Shortly, i have attached a function (onUpdateStarted) to be triggered by the event "attachUpdateStarted" on the mTable. Then find the coresponding oModel and mess up with iLength. 

      Is this solution a correct one? 

      A simple example

      
      onInit: function () {
      ...
      this.byId("mTable").attachUpdateStarted(undefined, this.onUpdateStarted);
      ...
      },
      
      onUpdateStarted: function (oEvt) {
      // check reason
      if (oEvt.mParameters.reason ==="Change") {
      const itemsList = oEvt.oSource.oPropagatedProperties.oModels.xyzModel.getBindings().filter(binding => binding.sPath === '/items')
        if (itemsList.length === 1) {
              // Manipulate pagination
               itemsList[0].iLength = 666
         }
       }
      }​
      Thank you