Hi,
I am creating an app with Kendo UI for 2 and NativeScript via Telerik Platform's AppBuilder. I am using the Telerik Platform as a backend via the Everlive API. Due to having referenced related content types, I am using an expression, which limits the data page size to 50 rows.
I am either displaying via ListView or RadListView. Can anyone help me to enable LoadOnDemand to get the next page of the data when the user scrolls to the bottom of the
TIA,
David
4 Answers, 1 is accepted
The RadListView comes with out-of-the-box loadOnDemand functionality which you can use to implement to get the next content when the user scrolls to the bottom of the current list. Based on the article above you can also refer to the real example (used in the article) which can be found here.
There are some crucial points ni this example which I am going to cover in the lines below
- first, we are declaring our properties items and _numberOfAddedItems. While items will be used as our source of items the _numberOfAddedItems will be used to keep track on how many items we have currently loaded and then when the user scrolls to the bottom and active the loadOnDemand callback we will download the data based on this counter. The initial value of 0 items will be assigned to the initial data load before the items are added and then we will increase the value with 1 for each item pushed into the source array.
- when all of the above is done we are ready to implement the loadOnDemnad functionality. Notice that there are minor differences in the iOS and Android templates so you will need to provide platform-specific files for both platforms if building for both iOS and Android.
- The first thing we need to do is to set the loadMode and the loadMoreDataRequested callback. In the linked example the loadMode is manual meaning we have to trigger the load on demand via button or other technique but if you want this to happen when the user scrolls to the bottom just change the loadMode to Auto
e.g.
<
lv:RadListView
loadOnDemandMode
=
"Auto"
loadMoreDataRequested
=
"{{ onLoadMoreItemsRequested }}"
/>
- the next step is to create our loadMoreDataRequested callback as done here. In the example, we have wrapped all in setTimeout just to mock some server delay which is not needed in a real-life project. What one will need to do is to create the API call and using the property _numberOfAddedItems to load the new items into the source array. While doing that we need to increase the counter of loaded items, notify the list view that the loading has ended and finally return true value as done here.
Regards,
Nikolay Iliev
Progress Telerik
Hi Nikolay,
Thank you for your very helpful reply. I also had a reply from Martin (via a support ticket). I have implemented both your suggestions and I am almost there.
Where I am still stuck is in updating the items with the new data. The first time it loads more data, it gets the next 20 rows but does not add them to the list, instead, it replaces them. The other problem is that after the first load, numberOfAddedItems is 70 but it still seems to load the first 50 rows again.
I am sure I am missing something obvious.
onLoadMoreItemsRequested(args: ListViewEventData) {
let that =
new
WeakRef(
this
);
let numberOfAddedItems: number = that.get()._numberOfAddedItems;
that.get()._service.getNextX(numberOfAddedItems)
.subscribe(
(data) => {
let arr: shared.Item[] = [];
data.forEach((item) => {
let newItem: shared.Item = {
"id"
: item.Id,
"data"
: item
};
arr.push(newItem);
});
that.get()._items$.next([...arr]);
//alert("_numberOfAddedItems= " + that.get()._numberOfAddedItems + "arr.length= "+arr.length);
that.get()._numberOfAddedItems += arr.length;
var
listView: RadListView = args.object;
listView.notifyLoadOnDemandFinished();
}, (error) => {
console.log(JSON.stringify(error));
}
);
}
Note that in the AppBuilder generated code _items$ is of type BehaviorSubject<Item[]> and items are added via _items$.next().
getNextX(start: number): Observable<any> {
//alert("getNextX("+start+")");
let promise: Promise<any> =
new
Promise(
(resolve, reject) => {
//alert(start);
let query =
this
._provider.query;
query.skip(start).take(20);
this
._data
.expand(
this
._expandExpression)
.get(query)
.then(data => resolve(data.result || []))
.
catch
(error => reject(error));
}
);
return
Observable.fromPromise(promise);
}
Thanks,
David
Thank you for the snippets and for the descriptive information! I have researched your code and what is happening is that you are creating a new empty array on each call of the onLoadMoreItemsRequested method. As this is called when the users trigger loadMoreData event this is erasing your initial items and pushing your new items to the emptied array instead of adding them.
Line where the array is reset
let arr: shared.Item[] = [];
What you can do to resolve this is to create your observable property (in our example called dataItems) and give its initial empty value in a init method for example as done here. Then in your onLoadMoreItemsRequested method, you can access this array and without resetting it to simply push the new items needed with your API call.
Now, I was not able to fully reproduce your code in working state as I do not have an API access with the used queris but still I suspect that both of you issue are closely related. Let me know if caching the source array in an observable property has resolved these problems for your case.
As a side note, I noticed that you are most likely using Angular based application. We have a very thorough tutorial that covers all aspect of creating an application with NativeScript and Angular here and you can use the full source code of the application as a reference on how to work with source array with an initial value and with a BehavourSubject (which in the context of this app is used for various scenarios including publishing newly created items).
Regards,
Nikolay Iliev
Progress Telerik
Hi Nikolay,
I have loadOnDemand functionality working. The issue was that after I switched to a reusing an array, the list would jump to the top on each extra load of data. This it seems is because RadListView does not work as expected with a BehaviorSubject when new items are added to the array.
I was advised by support to change from BehaviorSubject to ObservableArray and it now works correctly. I am able to scroll to the bottom of a list of 1750 rows without any problems.
If anyone else is facing similar issues, let me know and I will share the code.
David