Como implementar page loader no angular 13
Tags: angular, javascript, beginners, tutorial
Published: 2022-05-08 10:35:15

Esses dias tentei implementar uma forma de mostrar aos usuários a transição das páginas na aplicação, para isso fui procurar no google e por incrível que pareça conseguia encontrar uma solução em angular. Mas após uma pesquisa extensiva consegui criar a melhor solução pra este desafio.

Então respondendo a pergunta titulo do artigo, a resposta para a criação do page loader é o Router events, sempre que ocorre uma mudança como navegar para outra página, passar parâmetros a URL e outras relacionadas a rota, um evento é disparado, então para implementar a solução cabe a nós olhar para os eventos certos.

Para resolver o desafio separei a explicação em quatro pontos principais, a aplicação, a lógica das rotas e o loader.

## 1. Aplicação

Nesse ponto criaremos a aplicação que usaremos para implementar o loader, e para isso usaremos o angular CLI.

`ng new page-loader --routing`

O comando acima inicia um novo projeto de angular com o nome page-loader com as configurações iniciais de rotas.

Continuando criaremos três rotas novas para a aplicação, a page-one, page-two e page-three sendo elas lazy loaded. Vale notar que as rotas a serem criadas devem ser lazy loaded, tanto por questões de performance, como para que o exemplo funcione como esperado. Para isso criaremos as novas rotas com os comandos abaixo: 


`ng generate module page-one --route page-one --module app.module`

`ng generate module page-two --route page-two --module app.module`

`ng generate module page-three --route page-three --module app.module`

Tendo todos esses comandos executados com sucesso a estrutura da sua aplicação deve estar parecida com essa:


![Estrutura da aplicação](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mlzmo5xaken75iikrrcs.png)

E assim fica o `app-routing.module.ts`:

```typescript
import { NgModule } from '@angular/core'
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';


const routes: Routes = [
  {path: '', component: HomeComponent},
  { 
    path: 'second-page', 
    loadChildren: () => import('./second-page/second-page.module').then(m => m.SecondPageModule) 
  },
  { 
    path: 'third-page', 
    loadChildren: () => import('./third-page/third-page.module').then(m => m.ThirdPageModule) 
  },
  { 
    path: 'first-page', 
    loadChildren: () => import('./first-page/first-page.module').then(m => m.FirstPageModule) 
  },
];


@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }


;
```

Tendo a aplicação já organizada, já podes adicionar alguns textos e alguns estilos para as paginas para ter um ar mais agradável, ou podes também pegar os códigos que eu usei para esse projeto direto do meu [github](https://github.com/Rubalaine/angular-page-loader).

## 2. Lógica

Com a aplicação já criada, focaremos agora na mágica da coisa, para isso escutaremos aos eventos das rotas do angular no elemento mais acima da aplicação, o `app.component.ts`. O angular router dispõe de eventos do seu ciclo de vida, desde o inicio de uma navegação até o seu termino, como podes ver através do link, mas para o nosso caso, nós apenas olharemos para três desses eventos:

- **NavigationStart**: Ocorre quando é iniciado uma nova navegação;
- **NavegationEnd**: Ocorre quando uma navegação é concluída com sucesso;
- **NavigationError**: Ocorre quando há um erro durante a navegação.

A resposta para o page loader está nos eventos acima, ao escutá-los podemos mudar o estado da nossa aplicação de forma dinâmica, ou seja quando estiver a iniciar uma navegação, mostraremos o loader e o mesmo pode ser removido após o termino ou erro durante a navegação. Tendo isso em conta o assim fica o nosso `app.component.ts`:

```typescript
import { Component } from '@angular/core'
import { Event, NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.less']
})
export class AppComponent {
  loading = false;
  constructor(private router: Router){
    this.router.events.subscribe((event: Event) => {
      if (event instanceof NavigationStart) {
        this.loading = true;
      }
      if (event instanceof NavigationEnd || event instanceof NavigationError) {
        this.loading = false;
      }
    })
  }
}


;
```

## 3. Loader

Como havia mencionado, o loader estará no componente mais acima da aplicação, assim o mesmo não será removido do dom durante a navegação, e sim será controlado pelo componente mais acima, o `app.component.ts`. Então colocaremos o nosso loader diretamente no `app.component.html`.

```javascript
<!-- div para mostrar a animação de loading --
<div *ngIf="loading" class="page-loading"></div>

<app-navbar></app-navbar>
<div class="container">
  <router-outlet></router-outlet>
</div>
```

A variável loading foi criada no app component, e é alterada de acordo com estado da rota, então, enquanto estivermos a navegar o page loader será mostrado e após terminar a navegação o mesmo será ágora já temos tudo quase pronto para o nosso page loader, só falta a animação e para isso eu criei uma animação do tipo progress loader inspirado no youtube. Mas podes usar qualquer uma a sua escolha para mostrar na tela enquanto a sua pagina é carregada.

```css
.page-loading
    position: absolute;
    top: 0;
    right: 0;
    width: 100%;
    height: 10px;
    z-index: 1234;
    background-color: transparent;
    &::after {
        content: "";
        position: absolute;
        left: 0;
        background-color: #77befc;
        width: 100%;
        height: 100%;
        animation: load 3s;
    }
}
@keyframes load {
    0% {width: 0;}
    10% {width: 20%;}
    25% {width: 40%;}
    50% {width: 60%;}
    75% {width: 75%;} 
    100% {width: 100%;}
}
```

## Resultado final

![Resultado final](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kfsu7jogkzo7ztjbgor5.gif)

## Considerações finais

Pelo facto da aplicação do exemplo ser simples demais, pode ser difícil de ver o loader em ação, mas se a sua aplicação for mais grande e complexa, está solução te ajudará a dar uma melhor experiencia aos seus utilizadores, já que os mesmos agora terão um feedback agradável quando estiverem a navegar pelas paginas da sua aplicação.

Chegando até aqui, espero que este resultado tenha te ajudado assim como me ajudou.

Dê uma olhada no meu portfólio [kelven.dev](https://kelven.dev) tem muita coisa interessante por lá.