This project was generated with Angular CLI version 17.3.6..
https://github.com/leosasantos/porto-digital-agenda/archive/refs/heads/router.zip
Criar projeto do github
Criar projeto com angular cli
ng new porto-digital-agenda --no-standalone --routing --ssr=false
Realizando commit inicial
git add .
git commit -m "Initial commit"
git remote add origin <remote_repository_url>
git push -u origin master
Instalar biblioteca
npm install bootstrap
Configurar css no angular.json
Criando card
ng g c components/card
ng g i models/contato
nome: string;
telefone: string;
email: string;
tipo: number; // nacional -> 1 e internacional -> 2
@Input() contato: Contato|null = null;
em card.component.ts <h5 class="card-title">{{ contato?.nome }}</h5>
<p class="card-text">Telefone: {{ contato?.telefone }}</p>
<p class="card-text">Email: {{ contato?.email }}</p>
Usando o novo card com Input
contato: Contato = {
nome: "Fulano de Tal",
telefone: "81123456789",
email: "fulano@empresa.com.br",
tipo: 1
}
getContato(): Contato { return this.contato; }
- Usando no contato no card em app.component.html
```<app-card [contato]="contato"></app-card>```
Interpolação
{{ contato?.nome }}
{{ contato?.telefone }}
{{ contato?.email }}
Property Binding
isContatoInternaciona(){
if(this.contato?.tipo == 1){
return false;
} else {
return true;
}
}
<div>
<!-- https://icons.getbootstrap.com/icons/pin-map-fill/ -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pin-map-fill" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M3.1 11.2a.5.5 0 0 1 .4-.2H6a.5.5 0 0 1 0 1H3.75L1.5 15h13l-2.25-3H10a.5.5 0 0 1 0-1h2.5a.5.5 0 0 1 .4.2l3 4a.5.5 0 0 1-.4.8H.5a.5.5 0 0 1-.4-.8z"/>
<path fill-rule="evenodd" d="M4 4a4 4 0 1 1 4.5 3.969V13.5a.5.5 0 0 1-1 0V7.97A4 4 0 0 1 4 3.999z"/>
</svg>
Contato internacional
</div>
[hidden]="isContatoInternaciona()"
na div para controlar sua exibiçãoEvent Binding
onClick() {
alert('botão clicado!');
}
<button class="btn btn-primary" (click)="onClick()">
<!-- https://icons.getbootstrap.com/icons/trash3-fill/ -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash3-fill" viewBox="0 0 16 16">
<path d="M11 1.5v1h3.5a.5.5 0 0 1 0 1h-.538l-.853 10.66A2 2 0 0 1 11.115 16h-6.23a2 2 0 0 1-1.994-1.84L2.038 3.5H1.5a.5.5 0 0 1 0-1H5v-1A1.5 1.5 0 0 1 6.5 0h3A1.5 1.5 0 0 1 11 1.5m-5 0v1h4v-1a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5M4.5 5.029l.5 8.5a.5.5 0 1 0 .998-.06l-.5-8.5a.5.5 0 1 0-.998.06m6.53-.528a.5.5 0 0 0-.528.47l-.5 8.5a.5.5 0 0 0 .998.058l.5-8.5a.5.5 0 0 0-.47-.528M8 4.5a.5.5 0 0 0-.5.5v8.5a.5.5 0 0 0 1 0V5a.5.5 0 0 0-.5-.5"/>
</svg>
Excluir
</button>
Criando uma lista de contatos em app.component.ts
contatos[2]
) contatos: Contato[] = [
{
nome: "Fulano de Tal",
telefone: "81123456789",
email: "fulano@empresa.com.br",
tipo: 2
},
{
nome: "Beltrano de Tal",
telefone: "81234567981",
email: "beltrano@empresa.com.br",
tipo: 2
},
{
nome: "Ciclano de Tal",
telefone: "81345678912",
email: "ciclano@empresa.com.br",
tipo: 1
}
];
getContatos(): Contato[] {
return this.contatos;
}
Criando uma container para listar
<div class="container" style="display: flex"></div>
<app-card [contato]="contatos[0]"></app-card>
<app-card [contato]="contatos[1]"></app-card>
<app-card [contato]="contatos[2]"></app-card>
<div class="card" style="width: 20rem; height: 13rem; margin: 1rem">
Listar componentes com @for
@for (contato of contatos; track $index) {
<app-card [contato]="contato"></app-card>
}
Exibir informação de contato internacional com @if
@if (!isContatoInternaciona()) {
<!-- https://icons.getbootstrap.com/icons/pin-map-fill/ -->
<div>
...
</div>
}
Criar um serviço para recuperar contatos
ng g s services/contatos
contato.service.ts
contatos: Contato[] = [
{
nome: "Fulano de Tal",
telefone: "81123456789",
email: "fulano@empresa.com.br",
tipo: 2
},
{
nome: "Beltrano de Tal",
telefone: "81234567981",
email: "beltrano@empresa.com.br",
tipo: 2
},
{
nome: "Ciclano de Tal",
telefone: "81345678912",
email: "ciclano@empresa.com.br",
tipo: 1
}
];
public recuperarContatos(): Contato[] {
return this.contatos;
}
Removendo o array e adicionando o serviço no construtor e sua chamada em app.componnent.ts
constructor(
private contatosService: ContatosService
){ }
getContatos(): Contato[] {
return this.contatosService.recuperarContatos();
}
@for (contato of getContatos(); track $index) {
Criar o componente listar
Criar o componente listar contatos
ng g c pages/listar
Copiar o conteudo do listar de app.component.ts para .componennt.ts
export class ListarComponent {
constructor(
private contatosService: ContatosService
){ }
getContatos(): Contato[] {
return this.contatosService.recuperarContatos();
}
}
Copiar o conteudo do container de app.component.html para listar.componennt.html
<div style="display: flex">
@for (contato of getContatos(); track $index) {
<app-card [contato]="contato"></app-card>
}
</div>
ng g c pages/incluir
<header class="d-flex flex-wrap justify-content-center py-3 mb-4 border-bottom">
<a href="https://github.com/leosasantos/porto-digital-agenda/blob/master/" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto link-body-emphasis text-decoration-none">
<svg class="bi me-2" width="40" height="32"><use xlink:href="#bootstrap"></use></svg>
<span class="fs-4">Agenda Telefônica</span>
</a>
<ul class="nav nav-pills">
<li class="nav-item"><a href="#" class="nav-link">Listar</a></li>
<li class="nav-item"><a href="#" class="nav-link">Incluir</a></li>
</ul>
</header>
Criando rotas
Criar rotas em app-routing.module.ts
const routes: Routes = [
{ path: 'listar', component: ListarComponent },
{ path: 'incluir', component: IncluirComponent },
{ path: '', redirectTo: '/listar', pathMatch: 'full'}
];
Adicionar renderização em app.component.html
<div class="container">
<router-outlet></router-outlet>
</div>
Adicionar os links em app.component.html
<li class="nav-item"><a routerLink="/listar" class="nav-link">Listar</a></li>
<li class="nav-item"><a routerLink="/incluir" class="nav-link">Incluir</a></li>
import {ReactiveFormsModule} from '@angular/forms';
...
@NgModule({
...
imports: [
...
// outros imports ...
ReactiveFormsModule,
],
...
})
export class AppModule {}
import { Component } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
@Component({ selector: 'app-incluir', templateUrl: './incluir.component.html', styleUrl: './incluir.component.css' }) export class IncluirComponent {
form = new FormGroup({ nome: new FormControl(), telefone: new FormControl(), email: new FormControl(), tipo: new FormControl(), });
}
- Ir em incluir.component.html e incluir o texto abaixo, o nosso componente de inclusão ficará visível, apesar de pouco elegante.
<form [formGroup]="form">
- Ir em incluir.component.html e adicionar classes de estilo do Bootstrap, o nosso formulário ficará com um estilo bem melhor.
- Ir em incluir.component.html e adicionar a submissão do formulário para o modelo.
<button type="submit" class="btn btn-primary"(click)="onSubmit()">Incluir
- Ir em incluir.component.ts e observar apertando F12 no browser que ao submeter dados, os mesmos já estão disponíveis no modelo.
onSubmit(){ console.log(this.form.value) }
- Ir em incluir.component.ts e evoluí-la, criando o objeto JSON que representa um contato e enviando ele para o serviço de inserção que será criado.
import { Component } from '@angular/core'; import { FormGroup, FormControl } from '@angular/forms'; import { ContatosService } from '../../services/contatos.service';
@Component({ selector: 'app-incluir', templateUrl: './incluir.component.html', styleUrl: './incluir.component.css' }) export class IncluirComponent {
constructor( private contatosService: ContatosService ){ }
form = new FormGroup({ nome: new FormControl(), telefone: new FormControl(), email: new FormControl(), tipo: new FormControl(),
});
onSubmit(){
let contato = {nome:this.form.value.nome,
telefone: this.form.value.telefone,
email: this.form.value.email,
tipo: +this.form.value.tipo,
}
this.contatosService.inserirContato(contato);
this.form.reset();
}
}
- Ir em contato.service.ts e evoluí-la, adicionando a funcionalidade de inserção. Basta voltar na listagem para observar que o contato foi incluído.
public inserirContato(contado: Contato){
this.contatos.push(contado); }
### Pipes
1. Criando seu pipe personalizado
- Ir no terminal e digitar o trecho abaixo para criar um pipe personalizado para colocar as letras maiúsculas.
$ ng g p capitalize
- Observe que foi criado o arquivo capitalize.pipe.ts, nele coloque o seguinte conteudo
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'capitalize' })
export class CapitalizePipe implements PipeTransform {
transform(value: any, args?: any): any { let result = ''; for (const v of value.split(' ')) { result += this.capitalize(v) + ' '; } return result; }
private capitalize(value: string) { return value.substring(0, 1).toUpperCase() + value.substring(1).toLowerCase(); } }
- Por fim ir em card.component.html e acionar o pipe criado
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.