html - Smidigt ladda meddelanden Angular 8
Jag skriver en slags chattapplikation med Angular 8 och här är vad jag vill uppnå: Min dialogkomponent som representerar en chatt mellan två användare får en sida med de senaste meddelandena som består av 10 meddelanden efter initiering. Div-elementet som innehåller dessa meddelanden rullar ner till det allra sista meddelandet. När en användare rullar upp och når en viss punkt laddas nästa sida. De två arrayerna förenas och användaren ser nu 20 meddelanden. Här är vad jag har hittills:
HTML :
<div>
<div #scrollMe [scrollTop]="scrollMe.scrollHeight" (scroll)="onScroll($event)" style="overflow-y: scroll; height: 400px;">
<ul>
<li *ngFor="let message of messages?.reverse()">
</ul>
</div>
</div>
Typescript :
loadMessages(page: number, itemsPerPage?: number) {
this.messageService.getMessageThread(page, itemsPerPage || 10)
.subscribe((res: PaginatedResult<MessageThread>) => {
if (this.messages == null) {
this.messages = res.result.messages;
} else {
this.messages = this.messages.concat(res.result.messages);
}
});
}
onScroll(event) {
if (event.target.scrollTop < 100) {
if (this.pagination.currentPage >= this.pagination.totalPages) {
return;
}
this.loadMessages(++this.pagination.currentPage);
}
}
Det fungerar, men problemet är att när jag slår ihop dessa två arrayer hoppar min rullningslist väldigt fult och eftersom jag håller rullningslisten så stannar den på samma plats och fortsätter ladda nästa sidor. Jag är väldigt ny på Angular och front-end i allmänhet så jag har en känsla av att jag missar något. Jag försökte hitta någon färdig lösning men kunde inte. All hjälp skulle uppskattas.
Observera att jag inte vill använda JQuery.
Svar #1
Flera saker:
Först behöver vi en laddningsflagga:
loading = false;
Sedan låter vi loadMessages returnera ett observerbart istället för att hantera resultatet:
loadMessages(page: number, itemsPerPage?: number) {
this.loading = true;
return this.messageService.getMessageThread(page, itemsPerPage || 10);
}
En separat metod handleResponse hanterar svaret genom att sätta loading till false och sammanfoga meddelandena.
Då kan vi ta hänsyn till fördröjningen av förfrågan i scroll-hanteraren och använda laddningsflaggan för att förhindra flera förfrågningar:
onScroll(event) {
// get the scroll height before adding new messages
const startingScrollHeight = event.target.scrollHeight;
if (event.target.scrollTop < 100) {
if (this.pagination.currentPage >= this.pagination.totalPages) {
return;
}
else if (!this.loading) {
this.loadMessages(this.pagination.currentPage).subscribe((res) => {
this.handleResponse(res);
// using setTimeout lets the app "wait a beat" so it can measure
// new scroll height *after* messages are added
setTimeout(() => {
const newScrollHeight = this.scrollDiv.nativeElement.scrollHeight;
// set the scroll height from the difference of the new and starting scroll height
this.scrollDiv.nativeElement.scrollTo(0, newScrollHeight - startingScrollHeight);
});
});
}
}
}
Stackblitz (uppdaterad)
