Angular: recuperando os dados de uma página após um recarregamento
Ao recarregar a página, o contexto de execução do JavaScript é recriado, e variáveis em memória são perdidas. Para preservar dados, como os de um formulário, podemos usar o localStorage, que mantém as informações mesmo após o recarregamento. Veja neste texto um exemplo prático sobre esse assunto.
![Angular: recuperando os dados de uma página após um recarregamento](/content/images/size/w1200/2024/12/angular-salvando-resgatando-estado-pagina.png)
Ao desenvolver aplicações Angular, é comum precisar preservar o estado da página após um refresh, garantindo que os dados que o usuário forneceu sejam mantidos, como em um formulário. Isso pode ser feito de algumas formas, dentre elas, salvar os dados no localStorage do navegador.
Introdução sobre o ciclo de vida do JavaScript
Quando acessamos uma página no navegador, diversos elementos são carregados, como o conteúdo HTML, arquivos CSS, scripts JavaScript, imagens, fontes, entre outros. Após o navegador interpretar os scripts, é criado um contexto de execução. Esse contexto representa o ambiente onde o JavaScript da página opera, permitindo a manipulação de elementos da DOM, execução de lógica de negócios e interação com APIs externas.
Por exemplo, o contexto de execução pode corresponder a um projeto Angular em funcionamento ou até mesmo a uma página estática, como esta que você está lendo agora. No entanto, ao pressionar F5 ou clicar no botão de atualizar do seu navegador, o contexto de execução atual é descartado, e um novo é criado. Isso significa que todas as variáveis, classes, instâncias de objetos e outros dados mantidos em memória pelo JavaScript são perdidos e reiniciados.
De forma prática, imagine que você preenche um formulário em uma página e, por algum motivo, decide recarregar essa página. Após o refresh, os dados do formulário não estarão mais presentes, porque o contexto anterior foi substituído. Esse comportamento é padrão no ciclo de vida do JavaScript em uma página web, ou seja, sempre que uma página é recarregada, é como se você formatasse seu computador e recomeçasse do zero.
É exatamente nesse ponto que surge a necessidade de salvar o estado da página. Preservar o estado ajuda a melhorar a experiência do usuário, evitando que informações sejam perdidas e permitindo que a interação continue de forma contínua, mesmo após um recarregamento. Técnicas como o uso de localStorage
, sessionStorage
, query params, cookies ou persistência de dados no servidor são algumas das abordagens mais comuns para solucionar esse problema.
Neste pequeno texto será apresentado o uso do localStorage
para gravar e resgatar valores, preservando assim o estado de um formulário.
![](https://consolelog.com.br/content/images/thumbnail/consolelog-sessionstorage-localstorage-1.jpg)
Gravando e resgatando o estado da página de um projeto Angular
O código abaixo foi desenvolvido utilizando Angular 19, mas a ideia e boa parte do código funcionará com versões mais antigas do framework.
A classe EstadoService
fornece métodos bem diretos para salvar qualquer valor no localStorage
. O motivo da escolha do localStorage
, é porque ao contrário do sessionStorage
, ele mantém os dados armazenados mesmo após o fechamento da aba ou do navegador. Também poderíamos salvar os valores nos cookies, contudo, os cookies são trafegados em todas as requisições ao backend, aumentando assim o tamanho do cabeçalho de requisição.
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class EstadoService {
salvar(chave: string, valor: string): void {
localStorage.setItem(chave, valor);
}
obter(chave: string): string | null {
return localStorage.getItem(chave);
}
limpar(chave: string): void {
localStorage.removeItem(chave);
}
}
estado.service.ts
Já no componente que contém o formulário, a lógica é bem simples. Deixei alguns comentários para facilitar o entendimento:
import { CommonModule } from '@angular/common';
import {
Component,
inject,
OnDestroy,
OnInit,
} from '@angular/core';
import {
FormControl,
FormGroup,
ReactiveFormsModule,
} from '@angular/forms';
import { debounceTime, Subscription } from 'rxjs';
import { EstadoService } from '../estado.service';
const CHAVE_FORM_EXEMPLO = 'teste';
@Component({
selector: 'app-formulario-exemplo',
templateUrl: './formulario-exemplo.component.html',
imports: [CommonModule, ReactiveFormsModule],
})
export class FormularioExemploComponent
implements OnInit, OnDestroy {
private readonly estadoService = inject(EstadoService);
private formularioSubscription!: Subscription;
formulario: FormGroup = new FormGroup({
texto: new FormControl<string>('', {
nonNullable: true,
}),
select: new FormControl<string>('', {
nonNullable: true,
}),
radio: new FormControl<string>('', {
nonNullable: true,
}),
checkbox: new FormControl<string>('', {
nonNullable: true,
}),
});
ngOnInit(): void {
this.carregarEstadoPagina();
this.monitorarSalvarEstadoPagina();
}
ngOnDestroy(): void {
this.formularioSubscription.unsubscribe();
}
limparFormulario() {
this.formulario.reset();
this.estadoService.limpar(CHAVE_FORM_EXEMPLO);
}
/**
* Verifica se existe um estado salvo anteriormente.
* Caso exista, é efetuado o parse do valor e atribuido
* ao `formulario`:
*/
private carregarEstadoPagina(): void {
const dadosFormulario = this.estadoService.obter(
CHAVE_FORM_EXEMPLO,
);
if (dadosFormulario === null) {
return;
}
try {
const objDadosForm = JSON.parse(dadosFormulario);
this.formulario.patchValue(objDadosForm);
} catch {
this.estadoService.limpar(CHAVE_FORM_EXEMPLO);
}
}
/**
* Sempre que o `formulario` sofre alguma alteração,
* pegamos seu valor e salvamos.
*/
private monitorarSalvarEstadoPagina(): void {
this.formularioSubscription =
this.formulario.valueChanges
// Aguarda 500ms após a última alteração de valor
// antes de emitir o evento no `subscribe`.
.pipe(debounceTime(500))
.subscribe(() => {
// O método `getRawValue()` retorna todos os
// valores do formulário, incluindo os campos
// desabilitados.
const formValue = this.formulario.getRawValue();
this.estadoService.salvar(
CHAVE_FORM_EXEMPLO,
JSON.stringify(formValue),
);
});
}
}
formulario-exemplo.component.ts
<h1>Formulário de Teste</h1>
<div>
<form [formGroup]="formulario">
<div>
<input
placeholder="campo 1..."
formControlName="texto" />
</div>
<div>
<select formControlName="select">
<option value=""></option>
<option value="1">Valor 1</option>
<option value="2">Valor 2</option>
</select>
</div>
<div>
<input
formControlName="radio"
type="radio"
value="radio1" />
Radio 1
</div>
<div>
<input
formControlName="radio"
type="radio"
value="radio2" />
Radio 2
</div>
<div>
<input
formControlName="radio"
type="radio"
value="radio3" />
Radio 3
</div>
<div>
<input type="checkbox" formControlName="checkbox" />
</div>
<div>
<button type="submit">Enviar</button>
<button (click)="limparFormulario()" type="reset">
Limpar
</button>
</div>
</form>
</div>
<div>
<!--
O JSONPipe funciona como o JSON.stringify(). Para
utilizá-los é necessário importar o CommonModule.
-->
<pre>{{ formulario.value | json }}</pre>
</div>
formulario-exemplo.component.html
Observe no resultado abaixo que após preencher o formulário e efetuar um "reload", os valores do formulário são mantidos:
![Navegador mostrando o conteúdo de localhost:4200: um formulário sendo preenchido. Após recarregar a página, os dados do formulário são carregados novamente.](https://consolelog.com.br/content/images/2024/12/angular-mantendo-estado-da-pagina-apos-refresh.gif)
É possível visualizar os dados salvos no localStorage
através do DevTools do navegador:
![DevTool do navegador mostrando os dados do localStorage](https://consolelog.com.br/content/images/2024/12/angular-salvando-estado-da-pagina-localstorage.png)
Considerações
Mesmo sendo um projeto simples, envolve o entendimento sobre o que acontece no navegador ao requisitar uma página HTML, sobretudo de quando o JavaScript é interpretado e executado, que é um conceito fundamental em projetos Angular. Vale mencionar que o entendimento dos mecanismos de storage do navegador são importantes e já foram alvo de estudo por aqui, deixo o link a seguir:
![](https://consolelog.com.br/content/images/thumbnail/consolelog-sessionstorage-localstorage.jpg)
Para finalizar, a ideia pode ser expandida e modificada, tudo dependerá dos requisitos do seu projeto.