Recentemente, escrevi um tutorial intitulado, Criação de um armazenamento de perfil de usuário com Node.js e um banco de dados NoSQLpois esse é um assunto e um caso de uso muito popular quando se trata de bancos de dados NoSQL. Nesse tutorial, criamos uma API usando Node.js e Couchbase para armazenar usuários, informações associadas a determinados usuários e sessões expiradas. No entanto, ele era estritamente relacionado ao back-end, sem interface com o usuário.
Queríamos usar a API de armazenamento de perfil de usuário e entender como criar, usando TypeScript e Angular, uma página de perfil que se comunica com cada um dos pontos de extremidade da API.
Este tutorial foi atualizado em 7 de janeiro de 2021 por Eric Bishard para trabalhar com o Angular 11!
Antes de continuar, presumimos que você tenha seguido o tutorial anterior. Também vamos supor que você tenha o CLI angular instalado.
Criar um projeto Angular com os componentes necessários
O front-end do cliente será rudimentar, mas o criaremos do zero. Do ponto de vista do design, ele não terá uma ótima aparência, pois este tutorial trata da funcionalidade e do trabalho com a nossa API. Você é quem decide se quer deixá-lo bonito e oferecer uma experiência do usuário melhor.
Na CLI do Angular, execute o seguinte comando:
|
1 |
ng novo couchbase-angular-blog-aplicativo |
O comando acima criará um novo projeto no caminho da CLI. Com o projeto criado, precisaremos criar um componente para cada uma das páginas esperadas do aplicativo.
Execute o seguinte com a CLI do Angular:
|
1 2 3 4 |
ng g componente login ng g componente registro ng g componente blogs ng g componente blog |
Serão criados quatro componentes de perfil de usuário do Angular, cada um com arquivos TypeScript e HTML apropriados. Antes de começarmos a adicionar lógica a eles, precisamos uni-los para fins de navegação usando o modelo de perfil de usuário do Angular abaixo.
Abra o arquivo src/app/app.module.ts e inclua o seguinte:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
importação { Módulo do navegador } de '@angular/platform-browser'; importação { NgModule } de '@angular/core'; importação { FormsModule } de '@angular/forms'; importação { HttpClientModule } de '@angular/common/http'; importação { Componente de aplicativo } de './app.component'; importação { Componente de login } de './login/login.component'; importação { RegistrarComponente } de './register/register.component'; importação { BlogsComponent } de './blogs/blogs.component'; importação { Componente de blog } de './blog/blog.component'; importação { RouterModule } de '@angular/router'; deixar rotas = [ { caminho: '', redirectTo: '/login', pathMatch: 'completo' }, { caminho: 'login', componente: Componente de login }, { caminho: 'registro', componente: RegistrarComponente }, { caminho: 'blogs', componente: BlogsComponent }, { caminho: 'blog', componente: Componente de blog } ]; @NgModule({ declarações: [ Componente de aplicativo, Componente de login, RegistrarComponente, BlogsComponent, Componente de blog ], importações: [ Módulo do navegador, FormsModule, HttpClientModule, RouterModule, RouterModule.forRoot(rotas) ], provedores: [], bootstrap: [Componente de aplicativo] }) exportação classe AppModule { } |
O código acima foi criado pela CLI do Angular, no entanto, adicionamos algumas importações de módulos principais e personalizados e os importamos junto com o rotas no @NgModule bloco.
Para ativar nossa navegação, precisaremos atualizar um arquivo. Abra o arquivo src/app/app.component.html e substitua todo o conteúdo pelo seguinte:
|
1 |
<roteador-saída></roteador-saída> |
Neste ponto, o projeto de perfil de usuário tem uma configuração básica com o Angular.
Vamos dar uma olhada no tratamento da criação de perfis de usuário e no login com as informações da conta.
Manipulação de login e registro
A primeira tela que o usuário verá é a tela de login. O objetivo aqui é coletar um nome de usuário e uma senha, enviá-los à API, obter um ID de sessão como resposta e usá-lo em todas as páginas futuras do aplicativo.
Abra o arquivo src/app/login/login.component.ts e inclua o seguinte código TypeScript:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
importação { Componente, OnInit } de '@angular/core'; importação { Cliente Http, HttpHeaders } de '@angular/common/http'; importação { Roteador } de '@angular/router'; @Componente({ seletor: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.css'] }) exportação classe Componente de login implementa OnInit { público entrada: qualquer; construtor(privado http: Cliente Http, privado roteador: Roteador) { este.entrada = { 'email': '', 'senha': '' }; } ngOnInit(): vazio { } público login() { se (este.entrada.e-mail && este.entrada.senha) { deixar cabeçalhos = novo HttpHeaders({ 'content-type': 'application/json' }); este.http.postagem('http://localhost:3000/login', JSON.stringify(este.entrada), { cabeçalhos: cabeçalhos }) .assinar(resultado => este.roteador.navegar(['/blogs'], { 'queryParams': resultado }) ); } } } |
Há algumas coisas importantes acontecendo no código acima, portanto, vamos detalhá-lo.
Nossa intenção é vincular um objeto a um formulário na marcação HTML. Esse objeto será o entrada variável. Na construtor definimos cada propriedade possível como um valor vazio que será refletido na interface do usuário.
Quando o usuário decide fazer login, as informações de cabeçalho apropriadas são definidas para a solicitação e o objeto é enviado ao servidor. Se for bem-sucedida, a resposta será um objeto com o ID da sessão. Vamos passá-lo para a próxima página como um parâmetro de consulta.
A marcação HTML que combina com esse TypeScript é encontrada no arquivo src/app/login/login.component.html e ele se parece com o seguinte:
Entrar
|
1 |
Uma observação que devo mencionar aqui é que, se você digitar a senha errada, não criamos nenhuma forma de informar ao usuário que o nome de usuário ou a senha usada não estava correta.
O que é importante aqui é o uso do [(ngModel)] que são usados para vinculação de dados. Também oferecemos navegação para a página de registro por meio do atributo [routerLink] atributo.
Então, como é o componente de registro?
Abra o arquivo src/app/register/register.component.ts e inclua o seguinte código TypeScript:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
importação { Componente, OnInit } de '@angular/core'; importação { Cliente Http, HttpHeaders } de '@angular/common/http'; importação { Roteador } de '@angular/router'; @Componente({ seletor: 'app-register', templateUrl: './register.component.html', styleUrls: ['./register.component.css'] }) exportação classe RegistrarComponente implementa OnInit { público entrada: qualquer; público construtor(privado http: Cliente Http, privado roteador: Roteador) { este.entrada = { 'firstname': '', 'lastname': '', 'email': '', 'senha': '' }; } ngOnInit(): vazio { } público registro() { se (este.entrada.e-mail && este.entrada.senha) { deixar cabeçalhos = novo HttpHeaders({ 'content-type': 'application/json' }); este.http.postagem('http://localhost:3000/account', JSON.stringify(este.entrada), { cabeçalhos: cabeçalhos }) .assinar(() => este.roteador.navegar(['/login']) ); } } } |
Você perceberá que o código de registro é semelhante ao código de login. Estamos apenas coletando dados de formulário e enviando-os para um endpoint de API diferente.
O HTML correspondente encontrado no arquivo src/app/register/register.component.html tem a seguinte aparência:
Registro
|
1 |
O HTML contém elementos de formulário vinculados ao [(ngModel)] bem como um link para a página de login.
Lembre-se de que, depois de fazermos o login, estamos passando a sessão para as páginas específicas do usuário. Isso nos permitirá obter as informações do usuário em nosso armazenamento de perfis.
Criação e exibição de artigos de blog para um usuário específico no Profile Store
Depois de fazer login, o usuário é levado a uma página em que pode visualizar uma lista de artigos de blog que escreveu. Lembre-se de que nosso backend está conectando documentos NoSQL por meio de um ID de perfil que estamos definindo.
Para visualizar os artigos do blog, o ID da sessão passado da página anterior precisa ser definido como um cabeçalho em uma solicitação. O resultado da solicitação pode ser imediatamente renderizado na tela.
Abra o arquivo src/app/blogs/blogs.component.ts e inclua o seguinte código TypeScript:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
importação { Componente, OnInit } de '@angular/core'; importação { Cliente Http, HttpHeaders } de '@angular/common/http'; importação { Roteador, ActivatedRoute } de '@angular/router'; @Componente({ seletor: 'app-blogs', templateUrl: './blogs.component.html', styleUrls: ['./blogs.component.css'] }) exportação classe BlogsComponent implementa OnInit { privado lado: string; público entradas: qualquer; público construtor( privado http: Cliente Http, privado roteador: Roteador, privado rota: ActivatedRoute ) { este.entradas = []; } público ngOnInit() { este.rota.queryParams.assinar(parâmetros => { este.lado = parâmetros['sid']; deixar cabeçalhos = novo HttpHeaders({ 'autorização': 'Portador ' + parâmetros['sid'] }); este.http.obter('http://localhost:3000/blogs', { cabeçalhos: cabeçalhos }) .assinar(resultado => { este.entradas = resultado; console.registro(resultado) }); }); } público criar() { este.roteador.navegar(['/blog'], { 'queryParams': { 'sid': este.lado } }); } } |
Esse arquivo segue uma estratégia semelhante à forma como lidamos com o login e o registro.
Em termos de variáveis, criamos uma variável privada chamada lado que manterá a sessão passada da página anterior. O entradas será uma matriz de entradas de blog para um indivíduo retornado do endpoint da API.
Quando a página é carregada, devemos exibir as entradas do blog. Nunca é uma boa ideia carregar ou solicitar dados de dentro do construtor portanto, em vez disso, usamos o método ngOnInit método.
|
1 2 3 4 5 6 7 8 9 10 11 |
público ngOnInit() { este.rota.queryParams.assinar(parâmetros => { este.lado = parâmetros['sid']; deixar cabeçalhos = novo HttpHeaders({ 'autorização': 'Portador ' + parâmetros['sid'] }); este.http.obter('http://localhost:3000/blogs', { cabeçalhos: cabeçalhos }) .assinar(resultado => { este.entradas = resultado; console.registro(resultado) }); }); } |
No ngOnInit podemos pegar os parâmetros passados e construir um cabeçalho de autorização. Em seguida, fazemos uma solicitação ao nosso endpoint que contém o cabeçalho.
Para criar uma nova entrada de blog, podemos passar o parâmetro lado para a próxima rota:
|
1 2 3 |
público criar() { este.roteador.navegar(['/blog'], { 'queryParams': { 'sid': este.lado } }); } |
Isso é exatamente como o que vimos na tela de login.
A marcação HTML que alimenta a interface do usuário não será mais complexa do que a lógica TypeScript que a alimenta. O HTML pode ser visto na seção src/app/blogs/blogs.component.html assim:
Blogs que você escreveu
|
{{ entry.blog.title }}
{{ entry.blog.content }}
A criação de uma entrada de blog terá uma lógica semelhante à que já vimos. Abra a seção src/app/blog/blog.component.ts e inclua o seguinte código TypeScript:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
importação { Componente, OnInit } de '@angular/core'; importação { Cliente Http, HttpHeaders } de '@angular/common/http'; importação { ActivatedRoute } de '@angular/router'; importação { Localização } de '@angular/common'; @Componente({ seletor: 'app-blog', templateUrl: './blog.component.html', styleUrls: ['./blog.component.css'] }) exportação classe Componente de blog implementa OnInit { privado lado: string; público entrada: qualquer; público construtor(privado http: Cliente Http, privado rota: ActivatedRoute, privado localização: Localização) { este.entrada = { 'título': '', "conteúdo: '' }; } público ngOnInit() { este.rota.queryParams.assinar(parâmetros => { este.lado = parâmetros['sid']; }); } público salvar() { se (este.entrada.título && este.entrada.conteúdo) { deixar cabeçalhos = novo HttpHeaders({ 'content-type': 'application/json', 'autorização': 'Portador ' + este.lado }); este.http.postagem('http://localhost:3000/blog', JSON.stringify(este.entrada), { cabeçalhos: cabeçalhos }) .assinar(() => este.localização.voltar() ); } } } |
No código acima, estamos inicializando os dados do formulário e recuperando o lado que foi passado da página anterior.
Quando tentamos salvar a entrada, construímos um cabeçalho apropriado que contém o ID da sessão e o enviamos para a API com os dados do formulário. Uma vez concluído, podemos navegar para trás na pilha.
O HTML para a interface do usuário dessa página está no arquivo src/app/blog/blog.component.html assim:
Nova entrada no blog
Manter a consistência em mente
Por padrão, o Couchbase tentará ser rápido, o que significa que ele pode retornar dados mais rapidamente do que a atualização dos índices. Quando isso acontece, você pode ter dados recém-criados ausentes em seus resultados.
Expliquei como corrigir isso em um tutorial anteriormas uma rápida recapitulação está abaixo.
|
1 2 3 4 5 6 7 8 9 10 11 |
const consulta = `SELECT * DE `blog` ONDE tipo = 'blog' E pid = $PID;` const opções = { scanConsistency: couchbase.QueryScanConsistency.RequestPlus, parâmetros: { PID: solicitação.pid } } aguardar agrupamento.consulta(consulta, opções) .então((resultado) => { console.registro(resultado.linhas) resposta.enviar(resultado.linhas) }) .captura((e) => resposta.status(500).enviar(e)) |
Em nosso blogs podemos definir a consistência da varredura e, nesse caso, estamos dizendo a ele para esperar até que o índice seja atualizado antes de retornar os dados. Essa é uma operação rápida, portanto, não pense que ela será rastreada quando você fizer isso. Apenas não será tão rápido quanto o padrão.
Nesse ponto, o front-end deve funcionar perfeitamente com o back-end!
Para executar os dois projetos juntos.
Primeiro, verifique se o Couchbase está instalado e se você tem um bucket chamado blog criado e o índice que criamos no tutorial da API.
Em seguida, execute a API REST do Node:
|
1 |
nó servidor |
Em seguida, execute o projeto Angular:
|
1 |
ng servir |
Registre-se, faça login, crie uma ou duas postagens de blog e verifique se a rota de blogs está mostrando cada um dos blogs que você criou.
Como você pode melhorar este projeto
Como mencionamos anteriormente, o projeto poderia usar CSS e layout personalizados, bem como validação de formulário e alertas ou notificações, caso o usuário tenha tentado usar a senha errada ou o título do blog exceda um determinado número de caracteres, ou se um erro tiver sido lançado porque a API não está sendo executada corretamente.
Criar um Edição do blog página e rota e um link do título das postagens do blog na página Rota/página de blogs.
Criar navegação e estrutura sofisticadas para o aplicativo.
Reordenar a lista de blogs na seção Rota/página de blogs ou configurar a capacidade de classificar blogs por título em ordem crescente ou decrescente.
Permita que os usuários façam login com logins sociais ou use este projeto que criamos e adicione uma rota de portfólio e outras páginas de suporte como um ponto de partida para seu próprio portfólio de desenvolvedor.
Crie um serviço Angular para lidar com o ID da sessão, de modo que não seja necessário transmiti-lo a cada evento de navegação.
Conclusão
Você acabou de ver como criar um front-end de cliente simples usando o Angular 11 e o TypeScript para o armazenamento de perfil de usuário que vimos em um exemplo anterior. Cada modelo de perfil de usuário do Angular é diferente, é claro. Esse front-end de cliente é um dos muitos exemplos possíveis de página de perfil de usuário de material angular para um front-end, porque esse é um aplicativo modular de pilha completa. Isso significa que o back-end pode estar em qualquer idioma e o front-end pode estar em qualquer idioma.
O código finalizado está disponível no GitHub em couchbaselabs / couchbase-angular-blog-app no GitHub.
Para obter mais informações sobre como usar o Couchbase com o Node.js, consulte o Portal do desenvolvedor do Couchbase.