Table dynamic loading SAPUI5 / UI5 - odata

I want to display a huge set of data in a SAPUI5-Table component. I used to implement these datatables with dynamically loading, which means that the table initially loaded ~50 records. After the user scrolled down far enough, the next set of 50 records were loaded into the table. This way it was possible for me to display a table of more than 160.000 entries without any performance issues.
Now I need to do the same with SAPUI5-Table. I already implemented the server side, the OData service is ready to use. I already implemented the clientside but without that dynamic loading. The page always tries to load all records out of the database.
How can i achieve this? Is there any premade way to implement this? I know that the OData service can be called with various parameters which specify the dataset it will deliver, but i dont know how to make the table to these calls while scrolling?

Generally, a table bound to an OData Model does the most of it for you.
If you´re using sap.m.Table you can take a look at the growing properties here.
An example on how to use paging with a sap.m.Table can be found in the Explored app in the List section.
Using sap.ui.table.Table the threshold property controls the fetch size and is described here. Additionally you can choose a navigationMode. It can be a Paginator as well as a Scrollbar.
A very simple example for sap.ui.table.Table looks like this:
var oModel = new sap.ui.model.odata.ODataModel("<yourURL>", true);
var oTable = new sap.ui.table.Table({
columns : [], //set up columns as usual
threshold : 50 //your fetch size here
});
oTable.setModel(oModel).bindRows("/<yourEntity>");

Related

Sorting OData model in SAPUI5

Dear SAPUI5 Developers,
I developed a SAPUI5 Fiori Worklist project by using WebIDE template projects.
In the Component.js file the OData model has been fetched.
var sServiceUrl = this.getMetadata().getManifestEntry("sap.app").dataSources.mainService.uri;
var oModel = new sap.ui.model.odata.ODataModel(sServiceUrl, {
json: true,
loadMetadataAsync: true
});
oModel.attachMetadataFailed(function() {
// Call some functions from APP controller to show suitable message
}, this);
this.setModel(oModel, "BrandSet");
This part of code causes a call to OData server to fetch data from the remote server.
Now I want to order the data in backend and then receive the data. Assume the sorting function has been implemented correctly in the backend.
Thus, if I use $orderby=name or $orderby=price it has to be sorted by name or price respectively.
In some toturial they said for ordering use sorter option inside of the XML view file. Like here:
https://sapui5.hana.ondemand.com/#docs/guide/c4b2a32bb72f483faa173e890e48d812.html
Now my questions are:
How to apply this sorting inside of the Component.js file where the Model is initiated?
The second question is how to apply this ordering when we apply a filter to the model? Like the example that in the following link applied filter:
https://sapui5.hana.ondemand.com/#docs/guide/5295470d7eee46c1898ee46c1b9ad763.html
In fact I am looking for a function or any kind of method that add the $orderby=xxx to the OData service call.
I found a way here: https://sapui5.hana.ondemand.com/docs/api/symbols/sap.ui.model.odata.ODataModel.html#constructor
If I use mParameters.serviceUrlParams then I can add some URL parameter to the service request but it has been said "these parameters will be attached to all requests". Does it mean if I add the $orderbywith this method then I can not get rid of that in the further requests on that data model for example for filtering?
An app would normally be structured a bit differently to what you propose. The general assumption is that there is a lot of data available from the backend and to load all this data at once can cause performance problems, particularly when used over a mobile phone network. Furthermore, the data is an oData Entity Set, that is, a list of many items of the same type, so the data would be presented in the UI with a list or table.
Typically the app would then show the data in some kind of list, such as sap.m.List or sap.m.Table. These controls are designed to work with large volumes of data and would load initially the first 20 items from the entity set. Only when the user scrolls down the list of data would additional items be loaded. Also, with these controls the user can decide to sort or filter the data according to certain fields in your data.
Assuming that your app is work like this, here is the standard approach.
The Main model (as defined in the manifest) would not be loaded in Component.js, but loaded via the binding defined in the xml views of the app. In the views you could define a fixed sort and/or filter in the binding or you could allow the user to set the sort and filter criteria. This would be handled programmatically in the respective controllers. Normally the changes that the user makes to the sort and filter would be applied separately. For example, he/she chooses an new sort order, the oData is reread and the new sort order shown in the UI. Then the user may chose a filter criteria, and this is applied too. Of course, in your programming logic in the controllers you would need to have applied any default sort and filter criteria and then maybe combine or replace these with the criteria selected by the user.
To see an example of this, I would suggest to look at the Template Application “SAP Fiori Master-Detail Application” in the WebIDE.

Vaadin: How to remove item from DB container grid

How do I remove a row from a container/item/grid/db/entity/bean/class/object/ID?
Also, what's the difference between all these?
Everyone seems to say these as if they were interchangeable.
Can I get a simple explanation of how these all work together?
I've been through dozens of youtube videos and tutorials, but I still can't see the big picture.
Simple task: Delete one row from a grid.
But then it starts getting bigger and more complex with nested beanitem container property field entities and I just can't make sense of it.
Thank you for all of your help in advance!
The Grid, Table or any other Vaadin Component used to present set of data use some implementation of the Container to store your data. A Component is a part of your User Interface, the <div> in your DOM which is seen by your end user. The Vaadin Containers contains your objects. The most widely used containers are:
IndexedContainer - default container for Grid and Table. You usually add items by calling addItem method on either container or related component. The disadvantage of using this type of container is that you are usually obligated to set appropriate properties (think of columns) on both items and the container itself,
BeanContainer - is able to receive Java objects that follows JavaBean convention. Thus it is able to automatically infer properties of your component,
SQLContainer - contains data stored in database. Constructed using SQL query. Can be setup to automatically update your database based on changes made by user in UI.
Items and IDs
Adding single items to some containers may look a bit complicated. There are a few ways to do this. They are described very well on a Vaadin website. Basically the ID is an unique object that you use to access corresponding Item. The Item is represents the single row in your component. Every Item have properties. You can access and make changes to your items in container using their IDs i.e.
table.getItem("uniqueId");
Usually, you don't operate directly on containers. The components expose basic Container interface methods via their API. In example implementation of AbstractSelect.getItem() component currently (Vaadin 7.5.9):
protected Container items;
public Item getItem(Object itemId) {
return items.getItem(itemId);
}
(AbstractSelect is a super class of other Vaadin components like Table and Grid)
It gets more complicated with properties of the items. Every Item have some properties (columns). And every Property has its corresponding ID. Using property ID you can access the value of the item in the specific column. The following code presents above - it adds one item with one property and sets its value:
Table table = new Table();
table.addContainerProperty("column1", String.class, "defaultValue");
Item item = table.addItem("uniqueId");
item.getItemProperty("column1").setValue("Black Friday");
Notice that it is perfectly safe to use String literals as IDs since underneath they are compared using equals()

Pagination with Alamofire and realm.io

I have an api which could look like http://URL/news/:lastloaded/:size where lastloadedand size is the range of objects the api should return. This api returns a list of different news, which i want to show in a tableView. However in order to make it effective i wan't to make some kind of pagination, so that not all objects is loaded into the tableView. This i've achieved through simple variables like
let pageSize = 20
var lastLoadedPage = 0
however how do i make sure that the database in my case realm.io always is up to date with all the news from the api. I can easily change the api and add more parameters if it makes this easier? What is best practice? i'm using Alamofire and realm.io
Realm itself doesn't actually require pagination. The data is saved straight to disk, and then only the properties that are required are lazily paged in as they are called. As such, it's very memory-efficient, so much to the point where managing blocks of objects in memory (like pagination works) isn't necessary.
If you want to 'simulate' pagination with Realm, it's simply a matter of querying for all of the objects as a List, and then pulling out a sub-set of the objects you wish to display.
That all being said, it's probably still wise to paginate your calls to the web API so you don't needlessly download more news items than you require, but once they're downloaded and saved to Realm, you won't need to worry about any similar device-side logic. :)

Loading model/service contents before table is shown on the screen

I have some complex problem in which I am supposed to get data from a service before my screen gets loaded.
I am using ODataModel in the application. What I want is, I want to populate data from a service and show it in another table in one of the columns while other columns of the table should have data from my static json.
I was trying to create one table and tie it with the data from the service we want but setting the table to invisible as I don't want to make use of this table. The purpose of creating this table is to have data from the service loaded and the purpose of setting it to invisible is not to show users the things of no use. But I got to know that, unless and until the table is rendered on the screen, we don't get the data from the model.
How can this be achieved? Help would be appreciated.
Thanks
Have a look at this example : http://jsbin.com/qilaf/2/edit?js,console,output
I have used a local JSON model instead of an OData model, but if you look at the console, it perfectly shows the program flow (and that the model is loaded prior to the table rendering):
controller.loadData() - data is loaded
view.createContent() - table is created (not yet rendered)
controller.onInit() - table now rendered
view.onAfterRendering() - everything is now rendered
On a sidenote, I would not advice loading a model from the view, but that's a matter of style/taste, this example was merely intended to show the creation/loading of a model is totally independent from the creation/rendering of UI controls

SmartGWT LiveGrid unable to apply style to grid records programmatically

I am using SmartGWT 2.5, specifically a ListGrid backed by a RESTDataSource.
The Server integration is achieved by way of a servlet, and I only need to implement fetchData(). The data is a List<Map<String, Object>> populated on the server side, converted into JSON and sent in the DSResponse. The Live grid backed by the datasource triggers a server fetch programmatically by way of grid.fetchData().
Requirement:
I wish to set a record base style (or custom style) based on the value of one of the record's attributes, which I send over from the server.
In order to do this, I have tried a DataArrivedHandler, where I iterate over the available rows, get the ListGridRecord from the grid using the row number, and use gridRecord.set_baseStyle(String stylename) or gridRecord.setCustomStyle(String stylename) to try and apply a greyed out css for that record. After this, I call grid.markForRedraw(), however to no effect. The CSS does not get applied.
I must mention that I have used the same css to grey out rows on a normal listGrid (no dataSource) very successfully.
Questions:
Is my strategy the right one?
Is there an alternative method to apply a style to a record based on an attribute value.
Your strategy is correct and I have successfully achieved your required functionality in code of mine. Make sure you are correctly getting the record and that the test attribute is present in it. I suggest a JSON.encode(record.getJsObj()) to see what your record actually is filled with. No need for markForRedraw() explicit call, as after the DataArrivedEvent has fired the ListGrid will redraw its view. Post a small code snippet if you need more help. Also as suggested from the comment from Alain, highlights might be another good option to look at.

Resources