Pagination in GlideRecord?

robby3
Tera Contributor

I'm trying to figure out if there is a way to do pagination in GlideRecord on my applications UI Page that will have a lot of data on it. I would like to limit to pages of say ~20 records.

After reading the documentation on the Wiki, setLimit and setLocation seemed to be the key. (Coming from MySql, this seems like "limit 0,20", exactly what I want to do.)

var oGR = new GlideRecord('XXXX-SomeTable');

oGR.addQuery('sys_id', sSysID);

oGR.setLimit(iItemsPerPage);

oGR.setLocation(iStartLocation);

oGR.query();    

but this returns "Function setLocation is not allowed in scope"


What are the alternatives to do this? I would really like to restrict my query to only returning the records I need. I could kludge it by getting the full recordset, then just limiting my rendering code, but it's a huge waste of system resources.


What are the best practices to do pagination in an application UI page.   There appears to be pagination on the kb_list UI page, though I have not been able to figure out how it's working yet... I think since it's scoped as global, it's a bit different.


Thanks!

-Robby




1 ACCEPTED SOLUTION

robby3
Tera Contributor

I just figured out the answer  



oGR.chooseWindow(iStartLocation, iEndLocation);



This works a similar way to "limit" does in MySql, but the second variable is the stop point, not the number of items.     I wish they would have listed this in the GlideRecord Wiki documentation page.



Hope this helps someone else having to decode kb_list


View solution in original post

9 REPLIES 9

Can this be used on a inbound REST to a standard ServiceNow API?


I have created next previous buttons for pagination, but on clicking the next button it is fetching 3 or 4, or max 5 records. i want constant 5 records to show.

I created a pagination routine for a service portal widget not too long ago. It took a bit of effort (especially if you want to jump to the beginning or ending of the list). I found it easiest to define the start and size parameters and then determine the end point in the chooseWindow() call by adding the size to the start point.

Here's some code snippets from my widget and script include to help you.

<style>
  .paginate {
    font-size : 12pt;
    text-align : center;
  }
</style>
<div ng-if="c.data.table.paginate && c.data.table.rowCount > 0" class="paginate">
  <span ng-click="c.data.table.disable.first || turnPage(-2)" ng-disabled="true" ng-class="{disabled : c.data.table.disable.first}">
    <i class="fa fa-backward fa-2x" aria-hidden="true"></i>
  </span>
  &nbsp;
  &nbsp;
  &nbsp;
  <span ng-click="c.data.table.disable.prevPage || turnPage(-1)" ng-disabled="true" ng-class="{disabled : c.data.table.disable.prevPage}">
    <i class="fa fa-caret-left fa-2x" aria-hidden="true"></i>
  </span>
  &nbsp;
  <!--
  <input type="number" ng-model="c.data.table.start" size="3">
-->
  {{c.data.table.start + 1}} to {{c.data.table.end}} of {{c.data.table.rowCount}}
  &nbsp;
  <span  ng-click="c.data.table.disable.nextPage || turnPage(1);" ng-disabled="true" ng-class="{disabled : c.data.table.disable.nextPage}">
    <i class="fa fa-caret-right fa-2x" aria-hidden="true"></i>
  </span>
    &nbsp;
    &nbsp;
    &nbsp;
  <span ng-click="c.data.table.disable.last || turnPage(2)" ng-disabled="true" ng-class="{disabled : c.data.table.disable.last}">
    <i class="fa fa-forward fa-2x" aria-hidden="true"></i>
  </span>
</div>

Client script

	$scope.turnPage = function(direction) {

		switch (direction) {
			case 2:
				c.data.table.start = c.data.table.rowCount - c.data.table.count;
				c.data.table.end = c.data.table.rowCount;
				break;
			case -2:
				c.data.table.start = 0;
				c.data.table.end = calculateEnd(c.data.table);
				break;
			case -1:
			case 1:
				c.data.table.start += (c.data.table.count * direction);
				c.data.table.end = calculateEnd(c.data.table);
				break;
		}

		if (c.data.table.start < 0) {
			c.data.table.start = 0;
			c.data.table.end = calculateEnd(c.data.table);
		}

		var url = '';
		var obj = {};
		var method = 'GET';

		switch (c.data.screen.mode) {
 			// Set up the scripted REST API URL based on which mode
			// the widget is running.
			// Include parameters for start= and count=
		}

		$http({
			method : method,
			url : url,
			headers : {"Content-type" : "application/json"},
			data : obj
		}).then(function success(response) {
			console.log('response=' + JSON.stringify(response, null, 4));
			// Process the response here
			// I like log statements to ensure I got the right data back
			console.log('count=' + c.data.table.count);
			console.log('start=' + c.data.table.start + ' end=' + c.data.table.end);
			console.log('c.data.table.list.length=' + c.data.table.list.length);
		}, function failure(response) {
			console.log('response=' + JSON.stringify(response, null, 4));
			spUtil.addErrorMessage('Error');
		});

	}

Script Include (to disable various arrow keys)

var Paginator = Class.create();
Paginator.prototype = {
    initialize: function() {
    },

	disable : function(start, count, rowCount) {
		
		var answer = {
			"nextPage" : ((start + count) >= rowCount),
			"prevPage" : (start <= 0)

		};
		
		return answer;
	},
	
    type: 'Paginator'
};

HTML

    <button  class="btn btn-primary" ng-show="c.data.current_page != 0" ng-click="getPreviousIdx()">Previous</button>
     <button  class="btn btn-primary" ng-show="c.data.count >= c.data.page_size" ng-click="getNextSetIdx()">Next</button>
Client Script

// pagination

$scope.getNextSetIdx = function(idx) {
	c.data.current_page = parseInt(c.data.current_page) + 1;
	c.data.action = "nextRecordIdx"
	c.server.update().then(function(r){
		c.data.action = undefined;


});

}	
	$scope.getPreviousIdx = function(idx) {
		c.data.current_page = parseInt(c.data.current_page) - 1;
		c.data.action = "nextRecordIdx"
		c.server.update().then(function(r){
			c.data.action = undefined;
});
Server Script

if (!input) {
			//data.records = [];
			data.page_size = 5;
			data.count = 5;
			data.current_page = 0;
		data.approvals = [];
		var approvalGR = new GlideRecord('sysapproval_approver');
		approvalGR.addQuery('state', 'Requested');
		approvalGR.addQuery('approver', gs.getUserID());
		approvalGR.addQuery('source_table',"!=", "");
		approvalGR.orderBy('sys_created_on');
		approvalGR.chooseWindow(data.current_page, data.page_size);
		approvalGR.query();
		
}
		}
	if (input && input.action == "nextRecordIdx") {
			//data.records = [];
			data.count = 0;
		 
			var startPage = input.current_page * input.page_size;
			var endPage = (input.current_page * input.page_size) + input.page_size;
		 
		data.approvals = [];
		var approvalGR = new GlideRecord('sysapproval_approver');
		approvalGR.addQuery('state', 'Requested');
		approvalGR.addQuery('approver', gs.getUserID());
		approvalGR.addQuery('source_table',"!=", "");
		approvalGR.orderBy('sys_created_on');
		approvalGR.chooseWindow(startPage, endPage);
		approvalGR.query();
		
		
		
		while(approvalGR.next()){
			data.count++;
}
else{ return data}
		
	}
}

});

Thanks for the reply, to be honest, I'm confused with your code, will try to understand it fully.

Here's my situation, I'm creating pagination functionality inside a widget as above, I took some help for this code from communinty : https://community.servicenow.com/community?id=community_blog&sys_id=4cac2225dbd0dbc01dcaf3231f96198b 

I've created a widget which has 3 sections inside it, first to show pending approvals, second to show  approval history, and a third custom approvals section.

Now by using this above functionality, I was able to paginate the first section(pending approvals), and using the same functions with different variables I'm trying to paginate the next section i.e Approval History, 

The problems which I'm facing with the second section are: 

When the page loads for the 1st time, it only shows the next buttons, but no records, i need to click the button once to get the records.

When I click the next button, records are getting fetched properly, but the list of records changes between 1 to 5, I want constant 5 records to show.

1st time on loading : -

find_real_file.png

when I press Next : 4 records

find_real_file.png

when I press Next for second time : 1 record 

find_real_file.pngand so on..

 

Please suggest something.

 

Thank You. 

     - Laukik

Update on this :

 What I've found is, when I query for Requested State, It gives me consistent 5 records in pagination, whenever I try to change the state to other than requested, i face the issue,( ie. fetching different number of records) as explained above.

Please help me with this ASAP.

 

Thanks,

Laukik.