I am trying to build infinite scrolling content horizontally. Following code does the job on the first load.
HTML:
<div >
<div >
<div *ngFor="let user of userList">
<ion-grid>
<ion-row>
{{user.name}}
</ion-row>
</ion-grid>
</div>
</div>
</div>
SCSS:
.thumnails{
overflow-x: scroll;
overflow-y: hidden;
.list-thumbnail{
height: 100%;
white-space: nowrap;
.img-thumb{
display: inline-block;
border: 1px solid #ddd;
border-radius: 4px;
padding: 3px;
}
}
}
::-webkit-scrollbar {
display: none;
}
After this, I need to fire a method when a user reaches the end on scroll. Ionic has the component ion-infinite-scroll
which works in vertical scroll but it's not firing when I use it with the above code.
Is there a way to fire an event at the end of the horizontal scroll?
CodePudding user response:
I suggest trying the ionScroll event from ion-content component.
Enable ionScroll like:
<ion-content [scrollEvents]="true" (ionScroll)="logScrolling($event)">
On logScrolling check to see if the scroll reached a certain point. If it did, add more data to your infinite scrolling content:
async logScrolling($event) { if($event.target.localName != "ion-content") { return; } const scrollElement = await $event.target.getScrollElement(); const scrollWidth = scrollElement.scrollWidth - scrollElement.clientWidth; const threshold = 50; if(scrollWidth < threshold) { //...load data here }}
I did not test it but it should work like that. Please let me know if you ran into any problems.
CodePudding user response:
Here is my solution. Is not beautiful and I did not test it for performance issues but it does exactly what you want
HTML:
<ion-content>
<div (scroll)="scrollEv($event)">
<div >
<div *ngFor="let user of userList">
<span hidden>{{ user.id }}</span>
<ion-grid>
<ion-row>
{{ user.name }}
</ion-row>
</ion-grid>
</div>
</div>
</div>
</ion-content>
TS:
userList: Array<any> = [];
// elements count till the end of list to trigger the `getData()` function
elementsToTrigger: number = 10;
constructor() { }
ngOnInit() {
this.getData();
}
scrollEv(ev) {
// get the last visible on screen element of the list by it's coordenates:
// x => the offsetWidth of the body - 5px so it doesn't get out of boundaries
// y => distance the list is from the top. Note that here the list is fixed at the top because it's the only element on screen, but if, at some point,
// it will scroll or be placed at someplace else you should get this distance manually before this next line.
let elByCoords = document.elementFromPoint(document.body.offsetWidth - 5, 0);
let elId = elByCoords.children[0].textContent;
// check if the last element visible on screen is the "elementsToTrigger'th to last" and if so get more data
// here you should also check if all data has been loaded so you don't keep sending requests to your backend
if ((this.userList.length - this.userList.findIndex(user => user.id === elId)) <= this.elementsToTrigger) {
this.getData();
}
}
getData() {
// here goes your logic to retrieve more results from database.
let startAt: number = this.userList?.length || 0;
let arr = [];
for (let i = startAt; i < startAt 50; i ) {
arr.push({ id: i, name: `User ${i}` });
}
this.userList = (this.userList || []).concat(arr);
}
You may need to play a little with document.elementFromPoint(x, y)
to find the correct values