How to Request Entries Automatically in x Seconds Intervals - sapui5

In an XML view, I present a sap.m.Table with entries from an output ODataModel. Now the first 8 entries should be output for about 5 seconds and the remaining entries automatically reload, and switch in 5 second intervals, like a dashboard.
Here is an example: I have 30 entries.
At the beginning → Show entries 1 to 8.
After 5 seconds → Show entries 9 to 16.
After next 5 seconds → Show 17 to 24.
After next 5 seconds → Show 25 to 30.
Then repeat from the beginning.
Would you have any idea how I can do that? Could it possibly realized on the routing function with transfer of the required parameters to the URL?

I have made a Plunker to demonstrate how this can be achieved: Plunker Demo.
In a nutshell, you can leverage the startIndex and length parameters of the ManagedObject#bindAggregation method. More specifically, you use them to bind the table repeatedly.
this.byId("list").bindItems({
path: "/Meetups",
template: this.byId("template"),
templateShareable: true,
startIndex: start,
length: SLICE_SIZE
});
Because you continually rebinding the table, you can simply create the template object inside the XML view as a dependent, then you can access it via this.byId(...). We need to use the templateShareable flag to indicate that the template will be reused in further bindings (on the next tick).
<dependents>
<StandardListItem id="template" title="{Title}"
description="{Description}" counter="{MeetupID}" />
</dependents>
Regarding the routing, I made two routes: one initial ("default") route and one route which specifies the start index ("withStart"). Both of them pointing of course to the same view.
"routes": [{
"pattern": "",
"name": "default",
"target": "main"
}, {
"pattern": "/{start}",
"name": "withStart",
"target": "main"
}]
The transition between "slices" is done with the help of jQuery.sap.delayedCall. You can also use a IntervalTrigger instead, but it might cause some problems if the view is not the first one shown (as the first "slice" might not be shown for the full 5 seconds, depending of course on how you implement it).
jQuery.sap.delayedCall(INTERVAL, this, this.onTick, [start]);
Then a tick happens (i.e. when we need to change the "slice"), we simply do a navigation to the withStart route and increment the start index parameter. At this point, we can also check if we need to start from zero again (if the start index is greater than the total count).
start += SLICE_SIZE;
if (this.count && start >= this.count) {
start = 0;
}
this.getOwnerComponent().getRouter().navTo("withStart", {start: start});
In order to find out the total count (to be able to determine if you should go to zero), you can use the information from the List / Table's ListBinding.
var oBinding = this.byId("list").getBinding("items");
if (oBinding.isLengthFinal()) {
this.count = oBinding.getLength();
}
One problem that you might face in a multi-view application is that, if the user navigates between your "dashboard" view and some other view, the delayedCall might cause you to navigate back again to the "dashboard" view (i.e. the user might get "trapped" in the dashboard). To circumvent this, you could check to see if the view is visible first, before doing the navTo call.
Later edit:
For improving performance due to loading times you can use two different approaches:
Use the operation mode parameter when you are doing the binding. Setting it to Client will load all entries at once on the client side and the pagination mechanism will be done without further requests (at least in theory).
this.byId("list").bindItems({
path: "/Meetups",
template: this.byId("template"),
templateShareable: true,
startIndex: start,
length: SLICE_SIZE,
operationMode: OperationMode.Client
});
Do an initial load of the data using the ODataModel.read method, store the results into a JSON Model and then use the JSON Model for binding the list instead of the OData Model.
var oModel = this.getView().getModel("myJsonModel");
this.getView().getModel().read("/Meetups", {
success: function(oData) {
oModel.setData(oData);
}
});

Related

Filtering on ag-grid serverside not setting start row to 0 and end row to 100

Really need help on this, please.
Brief: I have implemented ag-grid serverside mode with partial store for lazy loading.
Problem Scenario : ServerSide mode, what happens is as you scroll more data is loaded, in terms of ag-grid more row blocks are loaded.
Lets say block size is 100 rows.
I scrolled 5-6 times, 5-6 request went to the server , loaded the data into the grid using success callback of getRows method in ServerSideDataSource Implementation.
You are currently viewing 500th-600th row in your viewport(the last request that went to server).
If you go and apply a fresh/change-existing filter on a column, the getRows method will get called but with request params having startRow 500 and endRow 600(rowBlock you are currently viewing).
This is the issue. I want that to be 0 and 100 respectively as you generally implement server-side filtering. It should be a fresh request to server right. ag-grid should recognise a new filter got applied so dump the existing rows on the grid send fresh request to server with 0 and 100 values.
This start and end row values are fine when you have already loaded data with filter applied till 500 and scrolling to load 500-600. But when the filter is first applied/ freshly applied(change from existing filter/ newly applied) you need the start and end rows to be 0 and 100 right. Help!!
Hi i came across this question while searching for this exact problem, looking around to the docs and couldn't find solution there. It's happening after they introduce serverSideStoreType: "partial | full".
my current workaround for this is to updating params.request.filterModel on your getRows datasource, if detect any changes on filterModel
getRows: function (params) {
//update startRow to 0 then detect changes
if(grid.filterModel != JSON.stringify(params.request.filterModel) ){
params.request.startRow = 0;
}
grid.filterModel = JSON.stringify(params.request.filterModel);
I got a method,after filter changed grid will be scrolled to the first row.
Angular :
filterChanged(params: FilterChangedEvent): void {
this.gridApi.ensureIndexVisible(0,null);
}
Javascript :
filterChanged(params) {
gridOptions.api.ensureIndexVisible(0,null);
}

Avoiding repetitive calls when creating reactfire hooks

When initializing a component using reactfire, each time I add a reactfire hook (e.g. useFirestoreDocData), it triggers a re-render and therefore repeats all previous initialization. For example:
const MyComponent = props => {
console.log(1);
const firestore = useFirestore();
console.log(2);
const ref = firestore.doc('count/counter');
console.log(3);
const { value } = useFirestoreDocDataOnce(ref);
console.log(4);
...
return <span>{value}</span>;
};
will output:
1
1
2
3
1
2
3
4
This seems wasteful, is there a way to avoid this?
This is particularly problematic when I need the result of one reactfire hook to create another (e.g. retrieve data from one document to determine which other document to read) and it duplicates the server calls.
See React's documentation of Suspense.
Particulary that part: Approach 3: Render-as-You-Fetch (using Suspense)
Reactfire uses this mechanics. It is not supposed to fetch more than one time for each call even if the line is executed more than once. The mechanics behind "understand" that the fetch is already done and will start the next one.
In your case, react try to render your component, see it needs to fetch, stop rendering and show suspense's fallback while fetching. When fetch is done it retry to render your component and as the fetch is completed it will render completely.
You can confirm in your network tab that each calls is done only once.
I hope I'm clear, please don't hesitate to ask for more details if i'm not.

Ag-Grid how to start loading records from the 500th?

I have a Ag-grid configured to work in infinity scroll
In the documentation, i found this example, which shows how to make a jump to the 500th record
But I'm looking for a way to start loading the grid directly to the 500th record
Maybe there is a property to set in the grid?
Or should I put in some event this code:
jumpTo500() {
if (this.gridApi.getInfiniteRowCount() < 501) {
this.gridApi.setInfiniteRowCount(501, false);
}
this.gridApi.ensureIndexVisible(500);
}
Which?
you can use ensureIndexVisible on onGridReady stage:
onGridReady(params) {
this.gridApi = params.api;
this.gridColumnApi = params.columnApi;
this.gridApi.ensureIndexVisible(499); <--- add this line
Note : this.gridApi.ensureIndexVisible(numberValue) number value should be less than infiniteInitialRowCount atleast for 1
infiniteInitialRowCount = 1000 - initial config
this.gridApi.ensureIndexVisible(999) - max
Update: another possible way via firstDataRendered
firstDataRendered Fired the first time data is rendered into the grid.
(firstDataRendered)="firstDataRendered($event)"
...
firstDataRendered(){
this.gridApi.ensureIndexVisible(499);
}
The ag-grid has a bug in infinity scroll mode
They are working to fix the bug
The solution proposed here is the best workaround I have found so far
But it does not permanently resolve the performance bug
In fact, looking in the logs you can see that the program always makes a first unnecessary request, to view the first 100 records
Only then, the workaround requires the correct records from 400 to 500

Apache Flink, get last event in the window

I'm working on a project where i have a window with a size of 4 days, with a step of 1 day
.timewindow(Time.days(4), Time.days(1))
and i have also a trigger
.trigger(new myTrigger)
onEventTime ---> Continue
onProccessingTime ---> Continue
clear ---> Purge
onElement---> (if element.isFinalTransaction) TriggerResult.FIRE_AND_PRUGE
isFinalTransaction is a boolean, when true it call FAP.
the mean question is how can i make it return true/false depending on if the element is the last in the window or not
is there any method that can tell us if the current element is the last one in the window?
is there any method that can tell us if the current window is done (before sliding) or not ?
From the abstract trigger class (https://github.com/apache/flink/blob/master//flink-streaming-java/src/main/java/org/apache/flink/streaming/api/windowing/triggers/Trigger.java)
The short answer is no. The method onElement is called for every element that gets added to the pane. When an element gets added it's impossible to know if it is the last element, because that information is not known until the next element comes (and we see if it was in this window or the next one).
However, one alternative would be to check if the element is sufficiently close to the end of the end of the window (because onElement has access to window e.g. if (timestamp > window.getEnd - delta) ...
However, I can not think of a use case in which I would recommend this. If you need access to the last element in the window, you should probably just use a WindowFunction and in the apply method get the last element of the input iterable (input.last).

sencha touch :: how to handle long lists on iOS

in my sencha touch app I need to display a list of over 600 entries of objects per selected customer.
imagine one store holds some customers, displayed in a list. each of them has some "has-many"-related sub-stores, one holding about 600 objects (with urls, title, description...). these sub-info has to be listed when you select one customer from the first list.
the problem is on iOS you have to wait some seconds before the list is shown and it is very slow to scroll/use. it seems that it slows down the whole app.
are there any other options to display long lists, maybe like pagination ore something...
thnx!
edit: I found this article and will test these thoughts soon: Link
edit2: here we go: https://github.com/Lioarlan/UxBufList-Sench-Touch-Extension
You can paginate your list by adding a pageSize param to your store and the listpaging plugin to your list. By setting the autoPaging option, you can control whether the data is loaded automatically or on user click. Below is an example:
// store
Ext.regStore('BarginsStore', {
model: 'BarginModel',
autoLoad: true,
pageSize: 6,
clearOnPageLoad: false,
sorters: 'category',
getGroupString: function(record) {
return record.get('category');
}
});
// list
this.list = new Ext.List({
store: 'BarginsStore',
plugins: [{
ptype: 'listpaging',
autoPaging: true
}],
singleSelection: true,
emptyText: '<p class="no-bargins">No bargins found matching this criteria.</p>',
itemTpl: '<div class="bargin-record">{name}</div>'
});
are there any other options to display long lists, maybe like pagination ore something...
Pagination. Smartphones have far more limited CPU and RAM resources than a desktop PC. A six hundred row table with several elements is not going to display well on the devices on the market now. Hell, it'll probably slow down desktop browsers. Paginate it.