Pagination in Classic ASP with VB Script - vbscript

I am using ASP/VB Script in my project but, i don't have much idea of Pagination in Classic ASP. I have designed a datagrid format using tables and looping. That table is filled by accessing database. As we have a huge amount of data to display, we need pagination.
Thanks in advance

The pagination problem is not inherently to ASP classic or VBScript. You need first to define which strategy to follow:
In the client:
Ajax style pagination (You can use a jQuery plugin like SlickGrid)
Linked pagination: Your page have links to page 1, page 2, etc.
Infite scrolling: This is a modern way to do pagination, with more results added to the page via ajax
In the server
Full DB results retrieve and return only the page asked. This is sometimes necessary.
Full DB retrieve but caching the result so subsequent page request come from the cache, not the DB
Ask the DB only the page asked (Different techniques depending on the DB engine)

There is a issue you need to be aware of... the built-in ASP record set will allow pagiing, however is not very efficient. The entire result set gets returned to the browser and then it locates the appropriate page and displays that data.
Think of it like this... your result set is a 4 shelf book case. When you ask for page one all 4 shelves of books get returned. The the display code says "Okay now only show page 1". If you then ask for page two... All four shelves of books gets returned and then the display code says "Okay give me page 4".
So, you should look for a paging solution that takes place on the server, inside the database. This way if you ask for page 15 of a 50 page result, the database will only return one shelf of books.
This google query should put you on the right track.
Edit: How SQL Paging Works
You must us a stored procedure
One of the input parameters is the page to view
The stored procedure filters the results on the server
Here is the basic concept of what happens inside the proc:
Step 1:
Create a temp table that stores the entire result set. My preference is to store only two values in this temp table. An identity seed value called RowId and the primary key of the result data. (I'm one of those people that believes in non-sensical identity seed keys)
Step 2:
Insert all the PKey values from the select statement into the temp table
Step 3:
Determine the StartRowId and EndRowId based on the input page parameter.
Step 4:
Select from the temp table using an inner join to the datatable on the PKey. In the where clause limit the result so the RowId (of the temp table) is between StartRowId and EndRowId. Make sure to Order By the RowId.

Set page size
recordset.PageSize = 100 ' number of records per page
Set the current page
recordset.AbsolutePage = nPage ' nPage being the page you want to jump to.
Other useful bits:
recordset.RecordCount ' number of records returned
recordset.PageCount ' number of pages based on PageSize and RecordCount
That's the basic info. You'll still need to loop through the appropriate number of records, and check the page number as it is passed back to the page.

Related

How to verify all rows in a HTML table that uses pagination during Cypress test?

In my Cypress test, I'm comparing the data on a HTML table (which is paginated) against expected values (which are stored in an array).
Also, the number of records in the table is can vary.
The current amount of rows appearing on the table (the first page) is 5 records, and users can navigate to the other records using the Next/Previous/First/Last buttons as usual.
Here is my latest Cypress code:
cy.task('queryDb', `${myQuery}`).then(result => {
for (var i = 0; i < result.length; i++) {
dashboard.name(i).should('have.text', ` ${result[i].name} `)
}
})
The above for loop works for the 5 companies that appear on the UI, but it doesn't loop through the records that aren't visible on the screen.
Can someone please tell me how I can validate the remaining companies in the table?
Do I only do this for the first 5 records, click the 'Next' button, & then do the same for the next 5 records?
There are two very different things, and you may want to separate them into two tests:
You want to test the method that populates your HTML table and make sure you retrieve the expected results
You want to ensure that your HTML table is working as expected with the proper pagination
For (1) it would be easier to test your HTML table query URL and see if you can query all without the pagination. In this way, you will be able to ensure that the retrieved data are correct.
For (2) you know the data are correct. You want to make sure they are displayed as expected.. It may be helpful to try and validate the next and previous buttons.
In this way, you will know if the problem comes from the logic inside your UI component or if it comes from your backend.

REST API - Retrieve previous query in dynamoDB

I have 100 rows of data in DynamoDB and a api with path api/get/{number}
Now when I say number=1 api should return me first 10 values. when I say number=2 it should return next 10 values. I did something like this with query, lastEvaluatedKey and sort by on createdOn . Now the use case is if the user passes number=10 after number=2 the lastEvaluatedKey is still that of page 2 and the result would be data of page 3. How can I get data directly. Also if the user goes from number=3 to number=1 still the data will not be of page 1.
I am using this to make API call based of pagination on HTML.
I am using java 1.8 and aws-java-sdk-dynamodb.
Non-sequential pagination in DynamoDB is tough - you have to design your data model around it, if it's an operation that needs to be efficient at all times. For a recommendation in your specific case I'd need more details about the data and access patterns.
In general you have the option of setting the ExclusiveStartKey attribute in the query call, which is similar to an offset in relational databases, but only similar and not identical. The ExclusiveStartKey is the key after which the query will continue, meaning data from your table and not just a number.
That means you usually can't guess it, unless it's a sequential number - which isn't ideal.
For sequential pagination, i.e. the user goes from page 1 to page 2, page 2 to page 3 etc. you can pass that along in the request as a token, but that won't work if the user moves in the other direction page 3 to page 2 or just randomly navigates to page 14.
In your case you only have a limited amount of data - 100 items, so my solution for your specific case would be to query all items and limit the amount of items in the response to n * 10, where n is the result page. Then you return the last 10 items from that result to your client.
This is a solution that would get expensive at scale (time + cost) though, fortunately not many people will use the pagination to go to page 7 or 8 though (you could bury a body on page 2 of the google search results).
Yan Cui has written an interesting post on this problem on Hackernoon, you might want to check it out.

Laravel - find offset of record in mysql results

I have a MySQL table of records with several fields.
These records are shown and updated live in the browser. They are displayed in an order choosen by the user, with optional filters also choosen by the user.
Sometimes a change is made to one of the records, and it may affect the order for a given user.
In order to position the message correctly in the list, I need to find where its new offset falls after the change to the record. Basically, I need to get the "id" for the record that now comes before it in the MySQL results, so that I can use Javascript on the client side to reposition the record on the screen.
In raw SQL, I'd do something like this:
SET #rank=0;
SELECT rank
FROM
(SELECT #rank:=#rank+1 AS rank,
subQuery.id AS innerQuery,
FROM ...{rest of custom query here}... as subQuery)
AS outerQuery WHERE outerQuery.innerQuery={ID TO FIND};
Then I can just subtract 1 from the resulting rank, and find the ID of the question that comes before the record in question.
Is this kind of query possible with Laravel's query builder? Or is there a better strategy than what I've come up with here to accomplish the same task?
EDIT: There are a lot of records. So if possible I'd like to avoid loading all the records into memory to find the offset of the record. They are originally loaded on the screen in an "infinite scroll" type method, since it would be too much to load all of them at once.

Smart pagination algorithm that works with local data cache

This is a problem I have been thinking about for a long time but I haven't written any code yet because I first want to solve some general problems I am struggling with. This is the main one.
Background
A single page web application makes requests for data to some remote API (which is under our control). It then stores this data in a local cache and serves pages from there. Ideally, the app remains fully functional when offline, including the ability to create new objects.
Constraints
Assume a server side database of products containing +- 50000 products (50Mb)
Assume no db type, we interact with it via REST/GraphQL interface
Assume a single product record is < 1kB
Assume a max payload for a resultset of 256kB
Assume max 5MB storage on the client
Assume search result sets ranging between 0 ... 5000 items per search
Challenge
The challenge is to define a stateless but (network) efficient way fetch pages from a result set so that it is deterministic which results we will get.
Example
In traditional paging, when getting the next 100 results for some query using this url:
https://example.com/products?category=shoes&firstResult=100&pageSize=100
the search result may look like this:
{
"totalResults": 2458,
"firstResult": 100,
"pageSize": 100,
"results": [
{"some": "item"},
{"some": "other item"},
// 98 more ...
]
}
The problem with this is that there is no way, based on this information, to get exactly the objects that are on a certain page. Because by the time we request the next page, the result set may have changed (due to changes in the DB), influencing which items are part of the result set. Even a small change can have a big impact: one item removed from the DB, that happened to be on page 0 of the result set, will change what results we will get when requesting all subsequent pages.
Goal
I am looking for a mechanism to make the definition of the result set independent of future database changes, so if someone was looking for shoes and got a result set of 2458 items, he could actually fetch all pages of that result set reliably even if it got influenced by later changes in the DB (I plan to not really delete items, but set a removed flag on them, for this purpose)
Ideas so far
I have seen a solution where the result set included a "pages" property, which was an array with the first and last id of the items in that page. Assuming your IDs keep going up in number and you don't really delete items from the DB ever, the number of items between two IDs is constant. Meaning the app could get all items between those two IDs and always get the exact same items back. The problem with this solution is that it only works if the list is sorted in ID order... I need custom sorting options.
The only way I have come up with for now is to just send a list of all IDs in the result set... That way pages can be fetched by doing a SELECT * FROM products WHERE id IN (3,4,6,9,...)... but this feels rather inelegant...
Any way I am hoping it is not too broad or theoretical. I have a web-based DB, just no good idea on how to do paging with it. I am looking for answers that help me in a direction to learn, not full solutions.
Versioning DB is the answer for resultsets consistency.
Each record has primary id, modification counter (version number) and timestamp of modification/creation. Instead of modification of record r you add new record with same id, version number+1 and sysdate for modification.
In fetch response you add DB request_time (do not use client timestamp due to possibly difference in time between client/server). First page is served normally, but you return sysdate as request_time. Other pages are served differently: you add condition like modification_time <= request_time for each versioned table.
You can cache the result set of IDs on the server side when a query arrives for the first time and return a unique ID to the frontend. This unique ID corresponds to the result set for that query. So now the frontend can request something like next_page with the unique ID that it got the first time it made the query. You should still go ahead with your approach of changing DELETE operation to a removed operation because it would make sure that none of the entries from the result set it deleted. You can discard the result set of the query from the cache when the frontend reaches the end of the result set or you can set a time limit on the lifetime of the cache entry.

Passing more than 3 items in a reports column link

I have a report that is listing students and I want a column to edit a student. I've done so by following this answer:
How do you add an edit button to each row in a report in Oracle APEX?
However, I can only seem to pass 3 items and there's no option to add more. I took a screenshot to explain more:
I need to pass 8 values, how can I do that?
Thanks!
Normally, for this you would only pass the Primary Key columns (here looks like #RECORD_NUMBER# only). The page that you send the person to would then load the form based on the primary key lookup only. If multiple users were using this application, you would want the edit form to always retrieve the current values of the database, not what happened to be on the screen when a particular person ran a certain report.
Change the Target type to URL.
Apex will format what to already have into a URL text field which magically appears between Tem3 and Page Checksum.
All you need to do is to add your new items and values in the appropriate places in the URL.
I found a workaround, at least it was useful to my scenario.
I have an IR page, query returns 4 columns, lets say: ID, DESCRIPTION, SOME_NUMBER,SOME_NUMBER2.
ID NUMBER(9), DESCRIPTION VARCHAR2(30), SOME_NUMBER NUMBER(1), SOME_NUMBER2 NUMBER(3).
What I did was, to setup items this way:
P11_ITEM1-->#ID#
P11_ITEM2-->#DESCRIPTION#
P11_ITEM3-->#SOME_NUMBER##SOME_NUMBER2#
Previous data have been sent to page 11.
In page 11, all items are display only items.
And P11_ITEM3 actually received two concatenated values.
For example, the calling page has columns SOME_NUMER=4 and SOME_NUMBER2=150
so, in pag1 11, P11_ITEM3 shows 4150
In page 11 I created a Before Footer process (pl/sql expression)
to set up new items, for example P11_N1 as source SUBSTR(P11_ITEM3,1,1)
and item P11_N2 as source SUBSTR(P11_ITEM3,2,3)
So, I had those items with corresponding values from the calling IR page.
The reason I did not pass the primary key only for new lookup access, is because i do not want to stress database performing new queries since all data are already loaded into page items. I've been an oracle DBA for twenty years and I know there is no need to re execute queries if you already have the information somewhere else.
These workarounds are not very useful for a product that bills itself as a RAD tool.
Just include a single quoted word in the select statement (Select col1, 'Randomword', col2 from table 1;)
Then define that column as a link and bingo! More items than 3 to select.

Resources