Infinite scroll é uma das formas que temos de criar paginação em nossos sistemas. Veja nesse artigo como implementar ele em um projeto mobile criado com Ionic na versão 3.
No final desse artigo você terá criado um app como o da imagem abaixo.
Para que possamos ter uma lista com dados reais, eu irei utilizar uma das API`s disponibilizadas pelo The New York Times (NYT). Para utilizar essa API, você irá precisar de uma KEY que pode ser encontrada no link: Developer NYT.
Criação do projeto
Nosso primeiro passo será a criação de um novo projeto. Para isso, execute o comando abaixo no seu terminal:
ionic start ionic-nyt blank
O comando a cima irá criar um novo projeto com uma configuração básica. Para testar ele, execute o seguinte comando ionic serve
no seu terminal e abra o seguinte endereço no seu navegador: http://localhost:8100/.
Criação do provider
O próximo passo será a criação de um provider para buscar os dados na API do NYT. Para isso, execute o seguinte comando no seu terminal:
ionic g provider nyt-api
Agora abra o projeto em uma IDE de sua preferência, para esse artigo eu irei utilizar o VS Code. Em seguida, atualize o seu provider com o código abaixo:
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import {NewsModel} from '../..//models/news-model'
/*
Generated class for the NytApiProvider provider.
See https://angular.io/guide/dependency-injection for more info on providers
and Angular DI.
*/
@Injectable()
export class NytApiProvider {
private apiUrl = 'https://api.nytimes.com/svc/topstories/v2/home.json?api-key={your key}';
constructor(public http: Http) {}
getTopStories(page): Observable<NewsModel[]> {
return this.http.get(this.apiUrl)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body || { };
}
private handleError (error: Response | any) {
let errMsg = `${error.status} - ${error.statusText || ''}`;
console.error(errMsg);
return Observable.throw(errMsg);
}
}
Agora para organizar o código, vamos criar uma Model para o nosso APP. Para isso, crie um novo diretório chamado Models e dentro dele um arquivo chamado news-model.ts, em seguida atualize ele com o código abaixo:
export class NewsModel {
constructor(
public title?: string,
public date?: Date) { }
}
Não podemos esquecer de adicionar HttpModule e NytApiProvider no nosso arquivo app.module.ts.
O próximo passo será injetar o NytApiProvider na nossa HomePage. Para isso, atualize o seu arquivo home.ts com o código abaixo:
import { Component } from "@angular/core";
import { NavController } from "ionic-angular";
import { NytApiProvider } from "../../providers/nyt-api/nyt-api";
import { NewsModel } from "../..//models/news-model";
@Component({
selector: "page-home",
templateUrl: "home.html"
})
export class HomePage {
data: any;
news: NewsModel[] = [];
errorMessage: string;
page = 1;
perPage = 0;
totalData = 0;
totalPage = 0;
constructor(public navCtrl: NavController, private nyt: NytApiProvider) {
this.getTopStories();
}
getTopStories() {
this.nyt.getTopStories(this.page).subscribe(res => {
this.data = res;
for (let i = 0; i <= 10; i++) {
let n = new NewsModel(
this.data.results[i].title,
this.data.results[i].published_date
);
this.news.push(n);
}
this.perPage = 10;
this.totalData = this.data.num_results;
this.totalPage = 10;
}, error => (this.errorMessage = <any>error));
}
doInfinite(infiniteScroll) {
this.totalPage = this.page * 10;
setTimeout(() => {
let result = this.data.results.slice(this.page * 10);
for (let i = 1; i <= this.perPage; i++) {
if (result[i] != undefined) {
let n = new NewsModel(result[i].title, result[i].published_date);
this.news.push(n);
}
}
this.page += 1;
infiniteScroll.complete();
}, 2000);
}
}
Analisando o código acima nós temos dois métodos: getTopStories que faz um request ao nosso provider e popula a nossa NewsModel e o doInfinite que é requisitado no nosso scroll.
Como a API do NWT não tem paginação, eu precisei fazer a páginação no APP, mas em cenário real, a melhor forma seria que essas regras ficassem no backend.
Agora atualize o seu arquivo home.html com o código abaixo:
<ion-header>
<ion-navbar>
<ion-title>
<img src="https://a1.nyt.com/assets/homepage/20171218-150818/images/foundation/logos/nyt-logo-379x64.png"/>
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-list>
<ion-item *ngFor="let n of news">
<h1>{{n.title}}</h1>
<h6>{{n.date}}</h6>
</ion-item>
</ion-list>
<ion-infinite-scroll (ionInfinite)="doInfinite($event)" *ngIf="totalPage < totalData">
<ion-infinite-scroll-content loadingSpinner="bubbles" loadingText="Loading more data..."></ion-infinite-scroll-content>
</ion-infinite-scroll>
</ion-content>
O ponto mais importando do código a cima está entre as linhas 18 e 20, onde utilizamos ion-infinite-scroll para fazer um request ao nosso método doInfinite() toda vez que o componente apresentar todos os itens que estão na nossa Model, até que o total da Model seja maior que o total de itens.
Caso você queira baixar a versão final do projeto criado nesse artigo, segue o seu link no GitHub.