Angular 6 Tutorial: Novas Características com Nova Potência
Angular 6 está fora! As mudanças mais notáveis estão no seu CLI e na forma como os serviços são injetados. Se você está procurando escrever seu primeiro aplicativo Angular 6 – ou Angular/Firebase – neste tutorial, vamos rever os passos básicos da configuração inicial e criar um pequeno aplicativo diário.
Angular 6: The Basics
Se você nunca usou Angular antes, deixe-me dar uma breve descrição dele e de como ele funciona.
Angular é um framework JavaScript projetado para suportar a construção de aplicações de página única (SPAs) tanto para desktop quanto para mobile.
O framework inclui um conjunto completo de diretivas e módulos que permitem implementar facilmente alguns dos cenários mais comuns para um aplicativo web, como navegação, autorização, formulários e relatórios. Ele também vem com todos os pacotes necessários para adicionar testes usando o framework Jasmine e executá-los usando os executores de testes Karma ou Protractor.
A arquitetura Angular é baseada em componentes, templates, diretivas e serviços. Ela fornece um mecanismo de injeção de dependência embutido para seus serviços, bem como uma ligação de dados bidirecional para conectar suas vistas com seu código de componente.
Angular usa TypeScript, um superconjunto digitado do JS, e tornará algumas coisas mais fáceis, especialmente se você vier de um fundo de linguagem digitado.
Angular 6: Novas funcionalidades
Um breve resumo das novas funcionalidades no Angular 6:
- Uma política de sincronização dos números das versões principais dos pacotes framework (
@angular/core
,@angular/common
,@angular/compiler
, etc.), CLI, Material, e CDK. Isto ajudará a tornar a compatibilidade cruzada mais clara no futuro: Você pode dizer de uma rápida olhada no número da versão se os pacotes chave são compatíveis entre si. - Novo
ng
Comandos CLI:-
ng update
para actualizar as versões dos pacotes de forma inteligente, actualizando as versões das dependências e mantendo-as em sincronia. (Por exemplo, ao executarng update @angular/core
todos os frameworks serão atualizados assim como o RxJS.) Ele também executará esquemas se o pacote os incluir. (Se uma versão mais recente inclui mudanças de quebra que requerem mudanças no código, o esquema irá atualizar seu código para você.) -
ng add
para adicionar novos pacotes (e executar scripts, se aplicável)
-
- Services agora referenciam os módulos que irão fornecê-los, ao invés de módulos referenciando serviços, como eles costumavam ter.
Como exemplo do que esta última mudança significa, onde seu código costumava parecer:
@NgModule({ // ... providers: })
…com esta mudança em particular no Angular 6, parecerá:
@Injectabe({ providedIn: 'root',})
Estes são chamados de provedores agitáveis por árvore e permitem que o compilador remova serviços não referenciados, resultando em pacotes de tamanho menor.
Angular 6 CLI
A ng
interface de linha de comando é uma peça muito importante do Angular e permite que você se mova mais rápido ao codificar seu aplicativo.
Com o CLI você pode scaffold sua configuração inicial do aplicativo muito facilmente, gerar novos componentes, diretivas, etc, e construir e executar seu aplicativo no seu ambiente local.
Criando um Projeto Angular 6
Okay, chega de conversa. Vamos sujar as mãos e começar a codificar.
Para começar, você vai precisar do Node.js e npm instalados em sua máquina.
Agora, vamos em frente e instalar o CLI:
npm install -g @angular/cli
Esta vai instalar o comando ng
CLI globalmente, devido à chave -g
.
Após termos isso, podemos obter o andaime inicial para a nossa aplicação com ng new
:
ng new my-memories --style=scss
Esta irá criar uma pasta my-memories
, criar todos os ficheiros necessários para ter a sua configuração inicial pronta para começar, e instalar todos os pacotes necessários. A chave --style=scss
é opcional e irá configurar o compilador para compilar arquivos SCSS para CSS, que precisaremos mais tarde.
Após a instalação estar completa, você pode cd my-memories
e executar ng serve
. Isto irá iniciar o processo de compilação e um servidor web local que serve a sua aplicação em http://localhost:4200
.
O que está acontecendo nos bastidores é que o CLI transporta todos os .ts
(arquivos TypeScript) para o vanilla JS, reúne todas as dependências necessárias da pasta de pacotes node_modules
, e produz o resultado em um conjunto de arquivos que são servidos através de um servidor web local que roda na porta 4200.
Project Files
Se você não está familiarizado com a estrutura de pastas do projeto Angular, a coisa mais importante que você precisa saber é que todo o código relacionado ao aplicativo vai para dentro da pasta src
. Você normalmente criará todos os seus módulos e diretivas nessa pasta seguindo sua arquitetura de aplicação (por exemplo, usuário, carrinho, produto.)
Configuração Inicial
Okay, até agora temos a configuração inicial para nossa aplicação. Vamos começar a fazer algumas alterações.
Antes de começar, vamos cavar um pouco na pasta src
. A página inicial é index.html
:
<!doctype html><html lang="en"><head> <meta charset="utf-8"> <title>MyMemories</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"></head><body> <app-root></app-root></body></html>
Aqui vemos algum HTML básico e a tag <app-root>
. Este é um componente Angular, e onde Angular 6 insere o nosso código de componente.
Encontraremos o ficheiro app/app.component.ts
, que tem o selector app-root
para corresponder ao que está no ficheiro index.html
.
O componente é uma classe TypeScript decorada, e neste caso, contém a propriedade title
. O @Component
decorador diz ao Angular para incluir o comportamento do componente na classe. Além do selector, especifica qual o ficheiro HTML a renderizar e quais as folhas de estilo a usar.
import { Component } from '@angular/core';@Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: })export class AppComponent { title = 'app';}
Se olharmos para app.component.html
veremos a ligação de interpolação {{title}}
. Aqui é onde todo o binding mágico acontece, e Angular irá renderizar o valor da propriedade título da classe e atualizá-la a qualquer momento que ela mudar.
<!--The content below is only a placeholder and can be replaced.--><div style="text-align:center"> <h1> Welcome to {{ title }}! </h1> <img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="></div><h2>Here are some links to help you start: </h2><ul> <li> <h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2> </li> <li> <h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2> </li> <li> <h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2> </li></ul>
Vamos continuar e atualizar o title
da classe para 'My Memories!'
.
...export class AppComponent { title = 'My Memories!';}...
Veremos o processo de mudança do compilador e o navegador atualizar para mostrar nosso título atualizado.
Isso significa que o Angular 6’s ng serve
relógios para nossas mudanças de arquivo e renderiza toda vez que uma mudança é introduzida em qualquer arquivo.
A fim de tornar a codificação mais amigável e evitar a actualização completa da página cada vez que fazemos alterações, podemos tirar partido do webpack Hot Module Replacement (HMR), que apenas actualiza a parte do JS/CSS que foi alterada em vez de produzir uma actualização completa para mostrar as suas alterações.
Configurando o HMR
Primeiro, precisamos de configurar o ambiente.
Criar um ficheiro src/environments/environment.hmr.ts
com o seguinte conteúdo:
export const environment = { production: false, hmr: true};
Actualizar src/environments/environment.prod.ts
e adicionar a bandeira hmr: false
ao ambiente:
export const environment = { production: true, hmr: false};
Alterar src/environments/environment.ts
e adicionar a bandeira hmr: false
ao ambiente lá também:
export const environment = { production: false, hmr: false};
Próximo no ficheiro angular.json
, actualize esta parte:
"projects": { "my-memories": { // ... "architect": { "build": { // ... "configurations": { "hmr":{ "fileReplacements": }, // ...
E em projects
→ my-memories
→ architect
→ serve
→ configurations
:
"projects": { "my-memories": { "architect": { // ... "serve": { // ... "configurations": { "hmr": { "browserTarget": "my-memories:build:hmr" }, // ...
Agora actualização tsconfig.app.json
para incluir o necessário types
(bem, digite) adicionando isto em compilerOptions
:
"compilerOptions": { // ... "types":
Próximo, vamos instalar o módulo @angularclass/hmr
como uma dependência de desenvolvimento:
npm install --save-dev @angularclass/hmr
Em seguida, configure-o criando um ficheiro src/hmr.ts
:
import { NgModuleRef, ApplicationRef } from '@angular/core';import { createNewHosts } from '@angularclass/hmr';export const hmrBootstrap = (module: any, bootstrap: () => Promise<NgModuleRef<any>>) => { let ngModule: NgModuleRef<any>; module.hot.accept(); bootstrap().then(mod => ngModule = mod); module.hot.dispose(() => { const appRef: ApplicationRef = ngModule.injector.get(ApplicationRef); const elements = appRef.components.map(c => c.location.nativeElement); const makeVisible = createNewHosts(elements); ngModule.destroy(); makeVisible(); });};
Next, atualização src/main.ts
para usar a função acima:
import { enableProdMode } from '@angular/core';import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';import { AppModule } from './app/app.module';import { environment } from './environments/environment';import { hmrBootstrap } from './hmr';if (environment.production) { enableProdMode();}const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule);if (environment.hmr) { if (module) { hmrBootstrap(module, bootstrap); } else { console.error('HMR is not enabled for webpack-dev-server!'); console.log('Are you using the --hmr flag for ng serve?'); }} else { bootstrap().catch(err => console.log(err));}
O que estamos fazendo aqui é fazer o bootstrap chamar uma função anônima, e em seguida perguntar se a bandeira environment.hmr
é verdadeira. Se for, nós chamamos a função previamente definida de hmr.ts
que ativou a substituição do módulo quente; caso contrário, nós o inicializamos como antes.
Agora, quando rodarmos ng serve --hmr --configuration=hmr
, estaremos invocando a configuração hmr
, e quando fizermos alterações em arquivos, obteremos atualizações sem uma atualização completa. O primeiro --hmr
é para webpack, e --configuration=hmr
é para Angular para usar o ambiente hmr
.
Progressive Web App (PWA)
A fim de adicionar suporte a Angular 6 PWA e habilitar o carregamento offline para o aplicativo, podemos fazer uso de um dos novos comandos CLI, ng add
:
ng add @angular/
Nota que estou adicionando a versão, uma vez que a última versão quando eu estava escrevendo este tutorial estava jogando um erro. (Você pode tentar sem ele e verificar se ele funciona para você usando simplesmente ng add @angular/pwa
.)
Okay, então depois de executarmos o comando veremos muitas mudanças no nosso projeto. As alterações mais importantes são que ele foi adicionado:
- Uma referência a
manifest.json
no ficheiroangular.json
assets, para que seja incluído na saída do build, assim como"serviceWorker": true
nos builds de produção - O ficheiro
ngsw-config.json
com a configuração inicial para guardar em cache todos os ficheiros necessários para a aplicação correr - A
manifest.json
meta tag no ficheiroindex.html
> - O ficheiro
manifest.json
próprio ficheiro, com uma configuração básica para o app - A carga do service worker no módulo app
ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production })
(note que o service worker só será habilitado em ambientes de produção)
Então, isto agora significa que quando o usuário acessar a URL pela primeira vez, os arquivos serão baixados. Depois disso, se o usuário tentar acessar a URL sem o serviço de rede, o aplicativo ainda funcionará puxando aqueles arquivos em cache.
Adicionando a biblioteca UI Material Angular 6
Até agora temos a configuração inicial, e estamos prontos para começar a construir nosso aplicativo. Para fazer uso de componentes já construídos, podemos usar a versão Angular 6 do Material.
Para instalar o pacote material
no nosso aplicativo, vamos novamente fazer uso de ng add
:
ng add @angular/material
Depois de rodarmos isso, vamos ver alguns novos pacotes adicionados e algumas configurações de estilo básico:
-
index.html
inclui a fonte Roboto e ícones Material -
BrowserAnimationsModule
é adicionado ao nossoAppModule
-
angular.json
tem o indigo-tema rosa já incluído para nós
Terá de reiniciar ng serve
para pegar no tema, ou você pode escolher outro tema pré-construído.
Basic Layout
Para ter o layout sidenav inicial, vamos usar os esquemas que vêm com o Material. Mas tudo bem se você quiser usar um layout diferente.
(Em resumo, os esquemas permitem que você aplique transformações em um projeto: Você pode criar, modificar ou apagar arquivos conforme necessário. Neste caso, ele cria um layout sidenav para nossa aplicação.)
ng generate @angular/material:material-nav --name=my-nav
Isto irá criar um componente sidenav com a configuração mínima pronta para começar. Não é fantástico?
Incluiu também todos os módulos necessários no nosso app.module.ts
.
Desde que estamos a utilizar o SCSS, precisamos de renomear o ficheiro my-nav.component.css
para my-nav.component.scss
, e em my-nav.component.ts
actualizar a referência correspondente styleUrls
para utilizar o novo nome.
Agora para fazer uso do novo componente, vamos para app.component.html
e remova todo o código inicial, deixando apenas:
<app-my-nav></app-my-nav>
Quando voltarmos ao browser, vamos ver o seguinte:
>
Atualizemos os links para termos apenas as duas opções que queremos.
Primeiro, vamos criar dois novos componentes:
ng g c AddMemoryng generate @angular/material:material-table --name=view-memories
(O segundo é um esquema de Material usado para criar uma tabela.)
Próximo, em my-nav
vamos atualizar para configurar os links e incluir o <router-outlet>
para exibir nossos componentes de conteúdo:
<mat-sidenav-container class="sidenav-container"> <mat-sidenav #drawer class="sidenav" fixedInViewport="true" ="(isHandset$ | async) ? 'dialog' : 'navigation'" ="(isHandset$ | async) ? 'over' : 'side'" ="!(isHandset$ | async)"> <mat-toolbar color="primary">Menu</mat-toolbar> <mat-nav-list> <a mat-list-item ="">Add Memory</a> <a mat-list-item ="">View My Memories</a> </mat-nav-list> </mat-sidenav> <mat-sidenav-content> <mat-toolbar color="primary"> <button type="button" aria-label="Toggle sidenav" mat-icon-button (click)="drawer.toggle()" *ngIf="isHandset$ | async"> <mat-icon aria-label="Side nav toggle icon">menu</mat-icon> </button> <span>my-memories</span> </mat-toolbar> <router-outlet></router-outlet> </mat-sidenav-content></mat-sidenav-container>
Também, em app.component.html
precisamos atualizá-lo para ter apenas o principal <router-outlet>
(ou seja remover <my-nav>
):
<router-outlet></router-outlet>
Próximo, em AppModule
incluiremos as rotas:
import { RouterModule, Routes } from '@angular/router';// ...imports: }, ]),]
Nota que estamos definindo MyNavComponent
como o pai e os dois componentes que criamos como crianças. Isto porque incluímos o <router-outlet>
em MyNavComponent
, e sempre que atingirmos uma dessas duas rotas, vamos renderizar o componente criança onde o <router-outlet>
foi colocado.
Depois disto, quando servirmos a aplicação devemos ver:
Build the App (A Memories Diary)
Okay, agora vamos criar o formulário para guardar novas memórias no nosso diário.
Temos de importar alguns módulos de material e o módulo de formulários para o nosso app.module.ts
:
import { FormsModule } from '@angular/forms';import { MatCardModule, MatFormFieldModule, MatInputModule, MatDatepickerModule, MatNativeDateModule } from '@angular/material';// ...Imports:
E depois em add-memory.component.html
, vamos adicionar o formulário:
<form #form="ngForm" (ngSubmit)="onSubmit()"> <mat-card class="memory-card"> <mat-card-title> Add a memory </mat-card-title> <mat-card-content> <mat-form-field> <input disabled matInput placeholder="Select the date..." ="memory.date" name="date" ="date"> <mat-datepicker-toggle matSuffix ="date"></mat-datepicker-toggle> <mat-datepicker disabled="false" #date></mat-datepicker> </mat-form-field> <mat-form-field> <textarea placeholder="Enter your memory..." rows="3" maxlength="300" matInput ="memory.text" name="memory"></textarea> </mat-form-field> </mat-card-content> <mat-card-actions> <button mat-button type="submit">Save me!</button> </mat-card-actions> </mat-card></form><pre> {{ memory | json }} </pre>
Aqui estamos a usar um mat-card
e a adicionar dois campos, um date
e um textarea
.
Nota que estamos a usar . Esta diretiva angular ligará a expressão
memory.date
e a propriedade memory
na classe uma à outra, como veremos mais adiante. ( é açúcar sintáctico – um atalho para executar a ligação de dados bidirecionais da classe para a vista e da vista para a classe. Isto significa que quando você insere texto na view,
memory.date
irá refletir essas alterações na instância da classe, e se você fizer alterações em memory.date
na instância da classe, a view irá refletir as alterações.)
Na add-memory.component.ts
, o código será parecido com isto:
import { Component, OnInit } from '@angular/core';@Component({ selector: 'app-add-memory', templateUrl: './add-memory.component.html', styleUrls: })export class AddMemoryComponent implements OnInit { memory: any = {}; constructor() { } ngOnInit() { } onSubmit() { console.log(this.memory); }}
Aqui, estamos inicializando a propriedade memory
vinculada via ngModel
. Quando o componente AddMemoryComponent
se instanciar, memory
será um objeto vazio. Então quando a diretiva ngModel
for executada, ele será capaz de atribuir o valor de entrada para memory.date
e memory.text
. Se não fizéssemos isso, receberíamos um erro de Cannot set property 'date/text' of undefined
.
Meanwhile, add-memory.component.scss
precisa ter:
.memory-card { min-width: 150px; max-width: 400px; width: 100%; margin: auto;}.mat-form-field { width: 100%;}
Desde que temos <pre> {{ memory | json }} </pre>
podemos ver o estado atual de memory
na vista. Se formos ao browser, aqui está o resultado até agora:
Na vista, ligamos o formulário via (ngSubmit)="onSubmit()"
à função onSubmit
na classe.
onSubmit() { console.log(this.memory); }
Então quando você clicar no botão “Save me!”, você terá a representação interna da entrada do usuário enviada para o log do console:
Angular 6 Tutorial: Conectando com Firebase
O que vamos fazer a seguir é conectar nosso projeto ao Firebase para salvar nossas memórias.
Primeiro, vamos para o console Firebase e criar um projeto lá.
Segundo, vamos instalar os pacotes firebase
e angularfire2
:
npm install firebase angularfire2 --save
> E depois em cada um destes três arquivos:
/src/environments/environment.ts
/src/environments/environment.hmr.ts
/src/environments/environment.prod.ts
…vamos adicionar nossa configuração do Firebase:
export const environment = {// ... firebase: { apiKey: '<your-key>', authDomain: '<your-project-authdomain>', databaseURL: '<your-database-URL>', projectId: '<your-project-id>', storageBucket: '<your-storage-bucket>', messagingSenderId: '<your-messaging-sender-id>' }};
Você pode obter os detalhes de configuração necessários para os arquivos acima clicando em “Adicionar Firebase à sua aplicação web” na página de visão geral do projeto.
Depois disso, vamos incluir os módulos do Firebase no nosso app.module.ts
:
import { AngularFireModule } from 'angularfire2';import { AngularFireDatabaseModule } from 'angularfire2/database';import { environment } from '../environments/environment';// ...Imports:
E em add-memory.component.ts
, nós injetamos o banco de dados no construtor e salvamos os valores do formulário para o banco de dados. Quando a promessa push do Firebase é bem sucedida, nós registramos o sucesso no console e reiniciamos o modelo:
import { AngularFireDatabase } from 'angularfire2/database';// ...constructor(private db: AngularFireDatabase) { }// ... onSubmit() { this.memory.date = new Date(this.memory.date).valueOf(); this.db.list('memories').push(this.memory) .then(_ => { this.memory = {} console.log('success') }) }
Precisa permitir o acesso público às regras do banco de dados, para que usuários anônimos possam ler e escrever para ele. Note que com esta configuração, qualquer utilizador poderá ler/alterar/apagar os dados da sua aplicação. Certifique-se de configurar suas regras de acordo antes de ir para a produção.
Tambem, para pegar as mudanças de ambiente você precisará reiniciar o ng serve
process.
Agora, quando voltarmos ao navegador e clicarmos no nosso botão salvar, veremos que a memória foi adicionada ao banco de dados:
Vejamos como podemos recuperar nossas memórias e exibi-las na tabela Material.
Voltar quando criamos a tabela usando ng generate @angular/material:material-table --name=view-memories', we automatically got a file
view-memories/view-memories-datasource.ts`. Este arquivo contém dados falsos, então precisaremos alterá-lo para começar a puxar do Firebase.
Em view-memories-datasource.ts
, removeremos o EXAMPLE_DATA
e definiremos um array vazio:
export class ViewMemoriesDataSource extends DataSource<ViewMemoriesItem> { data: ViewMemoriesItem = ;// ...
E em getSortedData
atualizaremos os nomes dos campos:
private getSortedData(data: ViewMemoriesItem) { if (!this.sort.active || this.sort.direction === '') { return data; } return data.sort((a, b) => { const isAsc = this.sort.direction === 'asc'; switch (this.sort.active) { case 'text': return compare(a.name, b.name, isAsc); case 'date': return compare(+a.id, +b.id, isAsc); default: return 0; } });}
Em view-memories.component.html
atualizaremos os nomes das colunas para date
e text
do nosso modelo de memória. Note que como salvamos a data em formato milissegundos, aqui estamos usando um pipe de data para transformar o valor para exibição em um formato de data mais humanamente amigável. Finalmente estamos removendo o ="dataSource.data.length"
do paginador, já que carregaremos os dados assincronamente do Firebase:
<div class="mat-elevation-z8"> <table mat-table #table ="dataSource" matSort aria-label="Elements"> <!-- Id Column --> <ng-container matColumnDef="date"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Date</th> <td mat-cell *matCellDef="let row">{{row.date | date:'short'}}</td> </ng-container> <!-- Name Column --> <ng-container matColumnDef="text"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Text</th> <td mat-cell *matCellDef="let row">{{row.text}}</td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> <mat-paginator #paginator ="0" ="50" =""> </mat-paginator></div>
Mude o view-memories.component.css
para view-memories.component.scss
e defina o estilo da tabela:
table{ width: 100%;}
Em view-memories.component.ts
, mudaremos o styleUrls
para refletir a renomeação acima para ./view-memories.component.scss
. Também atualizaremos o array displayedColumns
para ser e configuraremos a fonte de dados da tabela para obter dados do Firebase.
O que está acontecendo aqui é que estamos assinando a lista de memórias e quando recebemos os dados instanciamos o ViewMemoriesDataSource
e definimos sua propriedade de dados com os dados do Firebase.
this.subscription = this.db.list<ViewMemoriesItem>('memories').valueChanges().subscribe(d=>{ console.log('data streaming'); this.dataSource = new ViewMemoriesDataSource(this.paginator, this.sort); this.dataSource.data = d;});
Firebase retorna um array observável no estilo ReactiveX.
Nota que estamos lançando this.db.list<ViewMemoriesItem>('memories')
os valores tirados do 'memories'
caminho para ViewMemoriesItem
. Isto é cuidado pela angularfire2
biblioteca.
Também incluímos a chamada unsubscribe
dentro do onDestroy
gancho do ciclo de vida dos componentes angulares.
import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core';import { MatPaginator, MatSort } from '@angular/material';import { ViewMemoriesDataSource, ViewMemoriesItem } from './view-memories-datasource';import { AngularFireDatabase } from 'angularfire2/database';import { Subscription } from 'rxjs';import { map, first } from 'rxjs/operators';@Component({ selector: 'app-view-memories', templateUrl: './view-memories.component.html', styleUrls: })export class ViewMemoriesComponent implements OnInit, OnDestroy{ @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; dataSource: ViewMemoriesDataSource; /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ displayedColumns = ; subscription: Subscription; constructor(private db: AngularFireDatabase) { } ngOnInit() { this.subscription = this.db.list<ViewMemoriesItem>('memories').valueChanges().subscribe(d=>{ console.log('data streaming'); this.dataSource = new ViewMemoriesDataSource(this.paginator, this.sort); this.dataSource.data = d; }); } ngOnDestroy(): void { this.subscription.unsubscribe(); }}
Desenvolvendo para Firebase Hosting
Agora, para tornar nossa aplicação viva, vamos desdobrá-la para Firebase Hosting. Para isso, vamos instalar a CLI do Firebase, o que torna o comando firebase
disponível:
npm install -g firebase-tools
Agora podemos usar a CLI do Firebase para fazer login:
firebase login
Isso o levará a selecionar a sua conta do Google.
Próximo, vamos inicializar o projeto e configurar o Firebase Hosting:
firebase init
Só selecionaremos a opção Hosting.
Próximo, quando nos for pedido o caminho, vamos configurá-lo para dist/my-memories
. Quando nos perguntarem se devemos configurá-lo como um aplicativo de página única (ou seja, reescrever todas as URLs para /index.html
), responderemos “sim”.
Finalmente, clicaremos “File dist/my-memories/index.html já existe”. Sobregravar?” Aqui vamos dizer “não”.”
Isto irá criar os ficheiros de configuração do Firebase .firebaserc
e firebase.json
com a configuração fornecida.
O último passo é executar:
ng build --prodfirebase deploy
E com isso, teremos publicado o aplicativo para o Firebase, que fornece uma URL para nós navegarmos, como https://my-memories-b4c52.firebaseapp.com/view-memories, onde você pode ver minha própria demo publicada.
Wow, você já passou pelo tutorial! Espero que você tenha gostado. Você também pode conferir o código completo para ele no GitHub.
Um passo de cada vez
Angular é um framework muito poderoso para construir aplicativos web. Está lá fora há muito tempo e já provou ser para aplicações pequenas, simples e grandes e complexas – o Angular 6 não é exceção aqui.
Angular pretende continuar melhorando e seguindo novos paradigmas web como os componentes web (Elementos Angulares). Se você está interessado em construir aplicativos híbridos, você pode conferir Ionic, que usa Angular como sua estrutura subjacente.
Este tutorial cobriu passos muito básicos para começar a usar Angular, Material, e Firebase. Mas você deve levar em conta que para aplicações do mundo real, você precisará adicionar validação, e para tornar sua aplicação mais fácil de manter e escalar, você provavelmente quererá seguir as melhores práticas como o uso de Serviços, componentes reutilizáveis, etc. Isso terá de ser o assunto de outro artigo-hopefully, este foi suficiente para aguçar o seu apetite para o desenvolvimento angular!
Leave a Reply