Infinite scrolling Genexus SD - genexus

I need to implement an infinite scroll, that is, as the user scrolls in a grid that has "potentially" thousands of items. Initially I have an SDT and it is the one I show on the grid.
The idea is that:
The SDT loads from 20 to the cursor position
Show those 20 in the grid
Save the cursor position
This should be quick. As the user scrolls down, cycle 1, 2 and 3 are repeated until finished. So as not to overload the grid.
The most similar thing I found in the wiki is this:
http://wiki.genexus.com/commwiki/servlet/wiki?21311,HowTo%3A+External+Services+%28Scenario2%29,
Where variables count, Start (to say how many to load and from which position of the query to load) and the sdt that load the values ​​are defined. The point is that it is not clear to me how it works.
It loads in LOAD but nowhere do I see that the value of the Start variable is updated so I would always be loading the same 20 items.
If someone implements something so I can approach an explanation, some clue or a welcome xpz !!
Greetings and thanks

First of all, grids based on attributes already have this paging/infinite scrolling behavior on by default. I assume you are asking about grids based on variables.
The values of the &start and &count variables are automatically managed, and sent, by the GeneXus Smart Devices client application. The idea is that the service just needs to return the records in this range, and the client will automatically request more as the user scrolls.
Although it shouldn't have an effect on the service's implementation, the particulars are:
&start has the current (total) number of records returned by the service so far.
&count is a fixed value. It's the one set on the Rows property of the grid.
Therefore, the first request will have &start = 0 and &count = 10 (by default). The second request will have &start = 10 and &count = 10, then &start = 20 and so forth.
Note: It's important that if the client requests X elements, then exactly X are returned by the service. If this doesn't occur, then the client will assume that the data source is exhausted, and will make no more requests.

Related

Handling a controlled input when using RTK Query in React

When using RTK Query, you abstract away all the state management that comes with data fetching -- you call an endpoint and the documents are loaded into a variable, ready for use. Like so:
const {data: rangesInfo = []} = useGetRangesQuery(userId);
Let's say this rangesInfo variable contains a uniquely identifying ID, uuid, as well as a number, rangeValue, which specifies its position. This number can run from 0 to 100. For the sake of this example, let's imagine these ranges describe a user's food preferences. John is a 0 for sushi and a 100 for pizza. And as the end user clicks around the website, they can load other users' preferences, and so this set of ranges is constantly updating.
This all works fine -- you can call rangesInfo.map(range => <RangeComponent key={range.uuid} rangeValue={range.rangeValue}/>), and this will render a collection of children components, which all know how to display the UI of the actual HTML input[type=range].
But when using an range slider input in React, you must choose between either a controlled or an uncontrolled input. React's preference is for the input to be controlled by the state of its parent. In this case, the state of its parent is an RTK black box, and if you want to modify the cached data you must invalidate it, typically by triggering a mutation. This is RTK Query's term for a POST or an UPDATE request that will affect data in your backend. The thing is that in Chrome, a range input's onChange event triggers dozens of times a second, and it seems ridiculous to pummel your API with 40 requests when only the last one makes a difference.
That means we have to go with an uncontrolled component. The problem then becomes updating the display of the range when the props change. Because the props do change -- RTK is working fine -- but the props no longer have any bearing on the position of the range's value. (Remember, if you want to control an input's value via prop, you're no longer described an uncontrolled component!). If we could guarantee that the child components were remounted every time their props changed, we should be in the clear, but that wasn't my experience.
Even though those RangeComponents were given unique ids, and even though the docs suggest that this is sufficient, the new data was out of sync. When I loaded the page, I had User 0's info, and then I clicked on User 1 I still saw User 0. When I clicked on User 2, now User 1 popped in, and so forth.
My ultimately hacky solution was to attach a ref to the input range's DOM, and then use a side effect to dictate the its value, like so:
useEffect(() => {inputRef.current.value = props.rangeValue})
This solved my consistency problem, but introduced a ton of jank to the UX -- when I set the input range to a new state, it flickers back to its original position briefly.
Is there a way to solve this issue while staying in the RTK Query paradigm?
The no-jank, no-ref-necessary solution: Be extra sure that your child component's key is unique, because RTK is going to rerender it multiple times, and the render that "sticks" may not have the updated props at that point.
My fix was to append the value of the range to the key. So now the code looks like:
rangesInfo.map(range => <RangeComponent key={range.uuid + rangeValue} rangeValue={range.rangeValue}/>)
By linking the props and the keys together, you're guaranteeing that React will remount the child component.
Hope this saves somebody some time!

Computation in Oracle Apex not returning expected result

I am getting confused about computation points, such as before_header and after_header etc.
I have a computation, which needs to take a page item value, and then return as result.
The computation is a PL/SQL Function Body as below:
DECLARE
v_response varchar2(1500);
BEGIN
IF :P4_RENEWAL_REQUIRED = 'Yes' THEN
v_response := 'According to Register, a license renewal WILL BE required to maintain this registration. Please choose whether you agree or disagree with this statement.';
ELSE
v_response:='Forget about it...';
END IF;
return v_response;
END;
The page item :P4_RENEWAL_REQUIRED is a calculated field which is a SQL value, which relies on a database populated page item P4_RENEWAL_NOT_REQUIRED. It simply turns a Yes to a No and a No to Yes.
SELECT (CASE WHEN V('P4_RENEWAL_NOT_REQUIRED')='Yes' Then 'No' ELSE
CASE WHEN V('P4_RENEWAL_NOT_REQUIRED')='No' Then 'Yes' ELSE '??' END END) FROM DUAL
My computation will not return the result. The P4_RENEWAL_REQUIRED value will be clearly 'Yes' but the computation will return 'Forget about it'. If I go into page edit view, and then run the page again - the value shows the correct value of
'According to Register, a license renewal WILL BE required to maintain this registration. Please choose whether you agree or disagree with this statement.'
This implies to me that the computation is operating on an old session value of P4_RENEWAL_REQUIRED.
I am not really sure what the computation points have to do with this, but if I have data being returned via a Fetch Row process executing on After Header, which then is populating the fields in the regions such as P4_RENEWAL_NOT_REQUIRED, and then P4_RENEWAL_REQUIRED is being calculated....how do I get a computation to populate a field in another region which has a dependency on the existing page items?
I have tried making my computation execute before footer, before regions, after footer etc. but nothing works.
I am not sure how all the Before Footer works, or how the page items get populated in which point, when all of this is rendered server side.
For example if I set my computation to calculate "After Region" is it too late to then use that value IN a region as the regions have already been rendered?
If I need to calculate a value in my computation to use it in a region and use "Before Region" computation point, have the page items I need to use been tied to the page items by the underlying query at that point or am I too early.
Any help appreciated.
The "Source Used" should be set to "Always" since you want the value to reflect it's dependant value. When set to "Only when session state is null" the value will only be fetched when the session state is empty. After a first submit (or any other method of setting a value in session state, such as a computation) the source will no longer be retrieved each time. This'll give you the impression the value is old.
As for docs: it's usually really transparent, but where usually some confusion exists is when values are retrieved through the fetch row process: this process fetches the values for the relevant items (source=database column) and keeps them in memory for the duration of the render (an "in-memory session state"). These values will always be used for the item's source, though the values are NOT kept in session state afterwards (=when render finishes). You can verify this by checking session state after a page has rendered: all empty! I know I've read this somewhere, but it's not detailed in the docs themselves on how "fetch row" works.
Computations will set the value of the items in session state, persistently. Yes - you can use them to set the value of an item and it has this additional effect. This "caused" the problem here (in combination): simply deriving the value in the item source would work fine, as long as session state is not kept through a submit. Since a computation was used, the source was always disregarded since "only when session state is null" was used.
Performing a computation on a database column does set the session state though, but the in-memory session state and source type have overruled that value. After render the session state set through the computation still persists. When submitting the submitted values will once again be put in session state. So, that's a weird situation. This can be really weird though - try to avoid this as it'll be though to logic through this mess.
This does give meaning to the different computation points. You could compute an item after the rendering has ended, and the session state will be set. The item will have rendered with a value prior to the computation (if done after the render, otherwise, it depends on eg source) and then have the value persisted in session state.
I can't come up with an example as I've never had to use that situation though. Personally, the before and after region points don't mean much to me.
The before headers and after headers will usually be the most used points, and as with all processing, will be sequential. Use where appropriate.
Once again, in normal situations where the items are all derived through their source settings: they'll behave normal and no persistance to session state will occur. Processes (except "Fetch"!) and computations will make values persist in session state.

Load preliminary results, then reload when completed (Django or ajax)

I have a page that is taking far too long to load, because it requires 50+ objects to be fetched from the database.
I would like to load the page with only, say, the first 10 results, then let the server get on with loading the rest in the background, and then refresh the page.
Is there a way of doing something like:
def foo_view(request):
values = Foo.objects.all()[:10]
render_to_response(template, values, context_instance=...)
values = Foo.objects.all()
return render_to_response(template, values, context_instance=...)
Or is this a job for ajax? (Reloading the data as soon as the page has loaded.)
Thanks!
Edit:
It turns out that I was mistaken about the cause of the long loading time: actually fetching 50-100 objects from the database barely causes a delay.
There was a method in my template that resulted in n^3 database hits for my n items, when I should have been calling it once in the view function, and passing the results to my template.
AJAX is your solution. Add first 10 objects to your page. Then if user scrolls down fetch another 10 and so on. Like twitter. Or use pagination ? :)

How to efficiently allow a user to sort a list with AJAX

In my application, users have a list of items that they can put in any order they like. The database schema looks like this:
Items
+ Id : int
+ Name : string
+ Order : int
so when the user puts things in order, it sets the Order field accordingly, so that I can sort it later. Great.
Now, I want to make the sort ajax-y, such that the user can drag and drop items into order (and use up/down arrows), and it will just automagically save everything. (If you're familiar with Netflix, they do a similar thing.)
The issue I'm having is that in order to persist the user's changes as they make them, I will need to do an AJAX call every time they do something. If the user moves an item from position 10 to position 1, that implies that I have to update 10 records in that little ajax call. Meanwhile, the user may have queued up 3 more AJAX calls to update other records.
This seems inefficient and like it might be error prone (due to race conditions and so on, if the AJAX calls take a long time.) Should I be worrying about this? Is there a more efficient way to do this? If it makes a difference, I expect most users will have fewer than 5 items to sort.
Since Javascript can't synchronize code, I agree that it would be difficult to implement code that would be sure to avoid race conditions, although I did find this article on implementing a Mutex in Javascript.
However, personally I think that rather than choose an option that is likely to result in race conditions, I would go with one of the following options:
Create a save button above the items, that when clicked will save the order to the database.
Create a timer that will save the order every five seconds (or whatever), if something has changed. You would still want a save button for this, so the users could force a save.
I would lean towards the latter. Obviously in both cases you would want some visual cue to the users that they have unsaved changes (like changing the background color of the items, for instance). You would most likely want to implement something that makes sure the user wants to leave the page with unsaved changes if you go with either of those options (like in Gmail, when you have unsaved changes in an email that you are composing).

GWT - Load Search Results Incrementally - Without Pagination

Front End: GWT
Middle Ware: EJB
I have a search screen which can bring back several thousands of records (note that there is no pagination).
Right now, the GWT layer makes an RPC call to the RPC service and that makes a local call to the EJB, and gets back the sorted result set. Now the part that paints this data on the view, takes a lot of time.
I would like to know if any of you have created a similar page, where the records get loaded on to the screen, say 100 records at a time or so, using asynch calls so that the records in the page will get loaded sequentially, while the user is scrolling down gradually.
Do you mean something like this? http://gwt.google.com/samples/Showcase/Showcase.html#!CwCellList
Try to scroll that list and you will see.

Resources