Pular para conteúdo

Modelo de Referência para Angular

O que é o Framework Angular

Angular ⧉ é um framework de desenvolvimento web amplamente utilizado, desenvolvido pela Google, que simplifica a criação de aplicativos web robustos e escaláveis. Baseado em JavaScript e TypeScript, o Angular fornece uma estrutura sólida para a construção de interfaces de usuário modernas e dinâmicas. Ele é caracterizado por seu alto desempenho, arquitetura modular e extensibilidade, o que o torna uma escolha ideal para empresas que buscam desenvolver aplicações corporativas de alto nível.

O Angular promove o desenvolvimento baseado em componentes ⧉, o que significa que você pode criar componentes reutilizáveis que agilizam o desenvolvimento e garantem consistência na interface do usuário em toda a aplicação e utiliza o TypeScript ⧉ como linguagem principal, o que oferece a vantagem de tipagem estática. Isso ajuda a evitar erros de programação, melhorando a qualidade do código e a segurança do aplicativo.

Além disso, a ferramenta possui uma vasta biblioteca de módulos e extensões que facilitam a integração com outras tecnologias e serviços, como autenticação, gráficos e gerenciamento de estado.

Versões/Releases aplicáveis

A Magna Sistemas, por meio do MITH (Magna Innovation Technology Hub), estabelece padrões para o desenvolvimento de projetos. Em projetos Angular, há semelhanças importantes que demandam planejamento cuidadoso, definição de metas claras e estratégias eficientes para obter resultados consistentes. Assim como uma empresa busca maximizar a eficiência e a colaboração de sua equipe, a padronização do uso de bibliotecas promove a coesão e a reutilização de código, aumentando a produtividade e a qualidade dos projetos. A adoção de uma biblioteca padrão oferece uma base sólida para o desenvolvimento, garantindo consistência, manutenibilidade e escalabilidade nos projetos.

Os arquitetos e líderes têm a liberdade de preferir outras bibliotecas relevantes, porém, é importante destacar que a padronização contribui para melhorar a performance e facilitar a colaboração entre as equipes

Guia do desenvolvedor

Como um framework, o Angular inclui uma coleção de bibliotecas integradas que cobrem uma ampla variedade de funcionalidades. As bibliotecas Angular incluem roteamento, gerenciamento de formulários, comunicação cliente-servidor e mais.

Estrutura de diretórios

├── dist                                    # Diretório onde são gerados os arquivos finais de build da aplicação.
├── node_modules                            # Diretório onde ficam as dependências instaladas pelo npm ou yarn.
├── src                                     # Diretório principal do código-fonte da aplicação.
│   └── app                                 # Diretório da aplicação principal.
│       ├── core                            # Diretório que contém as funcionalidades e serviços base da aplicação.
│       │   ├── api                         # Diretório que contém a implementação de serviços de comunicação com APIs.
│       │   ├── services                    # Diretório que contém serviços de negócios usados em toda a aplicação.
│       ├── modules                         # Diretório que contém módulos (páginas) específicos da aplicação.
│       │   ├── admin                       # Ex.: Módulo administrativo.
│       │   │   ├── shared                  # Ex.: Diretório que contém componentes compartilhados para o módulo administrativo.
│       │   │   ├── admin.component.html    # Ex.: Arquivo HTML do componente principal do módulo administrativo.
│       │   │   ├── admin.component.ts      # Ex.: Arquivo Typescript do componente principal do módulo administrativo.
│       │   │   ├── admin.routes.ts         # Ex.: Arquivo Typescript utilizado para a configuração das rotas do módulo administrativo.
│       │   │   ├── admin.service.ts        # Ex.: Arquivo Typescript que contém as regras de negócio do módulo administrativo
│       │   ├── auth                        # Ex.: Módulo de autenticação.
│       │   └── landing                     # Ex.: Módulo da landing page.
│       ├── shared                          # Diretório que contém componentes e serviços compartilhados entre os módulos.
│       │   ├── components                  # Diretório que contém componentes compartilhados entre os módulos.
│       │   ├── icons                       # Diretório que contém um provider para busca de ícones usados na aplicação.
│       │   ├── layout                      # Diretório que contém componentes de layout compartilhados.
│       │   ├── models                      # Diretório que contém modelos de dados usados na aplicação.
│       │   ├── pipes                       # Diretório que contém pipes compartilhados entre os módulos.
│       │   ├── directives                  # Diretório que contém diretivas compartilhadas entre os módulos.
│       ├── app.component.html              # Arquivo de template HTML do componente principal da aplicação.
│       ├── app.component.scss              # Arquivo de estilos SCSS do componente principal da aplicação.
│       ├── app.component.ts                # Arquivo TypeScript do componente principal da aplicação.
│       ├── app.config.ts                   # Arquivo de configuração da aplicação.
│       ├── app.resolvers.ts                # Arquivo de resolvers para carregamento de dados antes da navegação.
│       └── app.routes.ts                   # Arquivo de configuração das rotas da aplicação.
├── assets                                  # Diretório que contém arquivos estáticos, como imagens, fontes, etc.
├── environments                            # Diretório que contém arquivos de configuração de ambiente (ex: desenvolvimento, produção).
├── styles                                  # Diretório que contém arquivos de estilos globais da aplicação.
├── index.html                              # Arquivo HTML principal que serve como entrada para a aplicação.
├── main.ts                                 # Arquivo TypeScript principal que inicializa a aplicação.
├── tools                                   # Diretório que contém scripts e ferramentas auxiliares para o desenvolvimento e build.
├── .dockerignore                           # Arquivo que especifica quais arquivos e diretórios devem ser ignorados pelo Docker.
├── .editorconfig                           # Arquivo de configuração para editores de código, garantindo consistência de formatação.
├── .eslintignore                           # Arquivo que especifica quais arquivos e diretórios devem ser ignorados pelo ESLint.
├── .eslintrc.json                          # Arquivo de configuração do ESLint, uma ferramenta de análise estática de código.
├── .gitignore                              # Arquivo que especifica quais arquivos e diretórios devem ser ignorados pelo Git.
├── .gitlab-ci.yml                          # Arquivo de configuração do GitLab CI/CD para automação de processos de build e deploy.
├── .prettierignore                         # Arquivo que especifica quais arquivos e diretórios devem ser ignorados pelo Prettier.
├── .prettierrc.json                        # Arquivo de configuração do Prettier, uma ferramenta de formatação de código.
├── angular.json                            # Arquivo de configuração principal do Angular CLI.
└── commitlint.config.js                    # Arquivo de configuração do Commitlint, uma ferramenta para garantir a conformidade das mensagens de commit.

Componentes

Os componentes são a base de uma aplicação Angular. Eles encapsulam a lógica e a interface do usuário, promovendo a modularidade e a reutilização. Cada componente é composto por:

  • Template: Define a interface do usuário usando HTML.
  • Classe: Contém a lógica e os dados do componente, escrita em TypeScript.
  • Estilos: Define a aparência do componente usando CSS ou SCSS.

Cada componente possue 4 arquivos:

  • nome-do-componente.component.html: O template do componente.
  • nome-do-componente.component.css (ou .scss): Os estilos do componente.
  • nome-do-componente.component.ts: A classe do componente.
  • nome-do-componente.component.spec.ts: Testes unitários para o componente.

Estrutura dos arquivos

  • HTML (.component.html)
<h1>{{ titulo }}</h1>
  • CSS (.component.css)
h1 {
    color: blue;
}
  • TypeScript (.component.ts)
import { Component } from "@angular/core";

@Component({
    selector: "app-nome-do-componente",
    templateUrl: "./nome-do-componente.component.html",
    styleUrls: ["./nome-do-componente.component.css"],
})
export class NomeDoComponente {
    titulo = "Olá, Angular!";
}

Rotas

As rotas no Angular são uma forma de navegar entre diferentes partes de uma aplicação sem recarregar a página. Elas permitem que você crie uma SPA (Single Page Application) com uma navegação fluida e rápida. As rotas são definidas usando a biblioteca Angular Router, que permite mapear URLs para componentes específicos.

Conceitos Principais

  • RouterModule: Um módulo que fornece a funcionalidade de roteamento e diretivas para navegação.
  • Routes: Um array utilizado na configuração das rotas da aplicação.
  • RouterOutlet: Uma diretiva usada para definir onde o conteúdo correspondente à rota deve ser exibido no arquivo HTML.
  • RouterLink: Uma diretiva usada para vincular elementos HTML a uma rota específica.

Implementação

Para implementar as rotas na aplicação, é necessário importar e configurar o RouterModule no módulo principal da aplicação.

import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";

import { HomeComponent } from "./home/home.component";
import { AboutComponent } from "./about/about.component";

const routes: Routes = [
    { path: "", pathMatch: "full", redirectTo: "inicio" }, // Define uma rota que redireciona da raiz para "/inicio"
    {
        path: "",
        canActivate: [AuthGuard], // Especifica que a rota requer que o guard "AuthGuard" seja ativado
        canActivateChild: [AuthGuard], // Especifica que os filhos da rota também requerem o guard "AuthGuard"
        component: LayoutComponent, // Define o componente que será usado ao carregar essa rota
        resolve: {
            // Busca os dados iniciais (ex.: domínio - opcional) antes de carregar o componente
            initialData: initialDataResolver,
        },
        children: [
            {
                path: "inicio", // Define uma rota filha para "inicio"
                loadChildren: () =>
                    import("app/modules/admin/inicio/inicio.routes"), // Carrega o módulo de rotas para "inicio" dinamicamente
            },
            {
                path: "dashboard", // Define uma rota filha para "dashboard"
                loadChildren: () =>
                    import("app/modules/admin/dashboard/dashboard.routes"), // Carrega o módulo de rotas para "dashboard" dinamicamente
            },
            {
                path: "users/:id", // Define uma rota filha para "users" com um parâmetro ID
                loadChildren: () =>
                    import("app/modules/admin/users/users.routes"), // Carrega o módulo de rotas para "users" dinamicamente
            },
        ],
    },
];

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

Para que o conteúdo das rotas seja exibido, você precisa adicionar a diretiva RouterOutlet no template principal da sua aplicação.

<router-outlet></router-outlet>

Em seguida, basta criar links de navegação, é ncessário utilizar a diretiva RouterLink.

<nav>
    <a routerLink="/inicio">Página Inicial</a>
    <a routerLink="/dashboard">Dashboard</a>
</nav>

Para rotas com parâmetros, é possível obter o valor utilizando a classe ActivatedRoute no arquivo Typescript do componente.

import { ActivatedRoute } from "@angular/router";

@Component({
    selector: "app-user",
    templateUrl: "./user.component.html",
})
export class UserComponent implements OnInit {
    userId: string;

    constructor(private _route: ActivatedRoute) {}

    ngOnInit(): void {
        this.userId = this._route.snapshot.paramMap.get("id");
    }
}

Rotas de Guarda (Guards)

Os guards são usados para proteger rotas, controlando o acesso com base em condições específicas.

import { Injectable } from "@angular/core";
import {
    CanActivate,
    ActivatedRouteSnapshot,
    RouterStateSnapshot,
    UrlTree,
} from "@angular/router";

import { Observable } from "rxjs";

import { AuthService } from "./auth.service";

@Injectable({
    providedIn: "root",
})
export class AuthGuard implements CanActivate {
    constructor(private _authService: AuthService) {}

    canActivate(
        next: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
    ):
        | Observable<boolean | UrlTree>
        | Promise<boolean | UrlTree>
        | boolean
        | UrlTree {
        // Retorna true ou false, a depender da lógica implementada para a proteção da rota.
        return this._authService.isLoggedIn();
    }
}

Formulários

Os formulários reativos (Reactive Form) no Angular oferecem uma abordagem baseada no modelo para gerenciar o estado dos campos de formulários cujos valores mudam ao longo do tempo. Diferente dos Template-driven Forms, que são baseados em templates, os Reactive Forms são baseados em código e fornecem mais controle e previsibilidade.

Conceitos Principais

  • FormControl: Representa um único campo de entrada de dado.
  • FormGroup: Agrupa vários controles de formulário em uma estrutura unificada.
  • FormArray: Gerencia um array de instâncias de FormControl ou FormGroup.

Implementação

Importando o módulo ReactiveFormsModule

Para usar os Reactive Forms, é necessário importar o módulo ReactiveFormsModule no módulo principal da aplicação.

import { ReactiveFormsModule } from "@angular/forms";

@NgModule({
    imports: [ReactiveFormsModule],
})
export class AppModule {}
Criando FormControls

Um FormControl pode ser criado e associado a um campo de entrada no componente.

import { Component } from "@angular/core";
import { FormControl } from "@angular/forms";

@Component({
    selector: "app-name-editor",
    template: `
        <label for="name">Name: </label>
        <input id="name" [formControl]="name" />
        <p>Value: {{ name.value }}</p>
        <button (click)="updateName()">Update Name</button>
    `,
})
export class NameEditorComponent {
    name = new FormControl("");

    updateName() {
        this.name.setValue("Nancy");
    }
}
Criando FormGroups

Um FormGroup agrupa múltiplos FormControl em uma estrutura de formulário.

import { Component } from "@angular/core";
import { FormGroup, FormControl } from "@angular/forms";

@Component({
    selector: "app-profile-editor",
    template: `
        <form [formGroup]="profileForm">
            <label for="first-name">First Name: </label>
            <input id="first-name" formControlName="firstName" />
            <label for="last-name">Last Name: </label>
            <input id="last-name" formControlName="lastName" />
        </form>
    `,
})
export class ProfileEditorComponent {
    profileForm = new FormGroup({
        firstName: new FormControl(""),
        lastName: new FormControl(""),
    });
}
Validando Formulários

As validações podem ser adicionadas aos controles para garantir a integridade dos dados.

import { Validators } from "@angular/forms";

profileForm = new FormGroup({
    firstName: new FormControl("", Validators.required),
    lastName: new FormControl("", Validators.maxLength(10)),
});
Exemplo Prático: Formulário de Edição de Perfil
import { Component } from "@angular/core";
import { FormBuilder, FormGroup } from "@angular/forms";

@Component({
    selector: "app-profile-editor",
    template: `
        <form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
            <label for="first-name">First Name: </label>
            <input id="first-name" formControlName="firstName" />
            <label for="last-name">Last Name: </label>
            <input id="last-name" formControlName="lastName" />
            <button type="submit">Submit</button>
        </form>
    `,
})
export class ProfileEditorComponent {
    profileForm: FormGroup;

    constructor(private fb: FormBuilder) {
        this.profileForm = this.fb.group({
            firstName: [""],
            lastName: [""],
        });
    }

    onSubmit() {
        console.warn(this.profileForm.value);

        // O resultado será um objeto com os valores informados nos inputs. Ex.:
        // {
        //     firstName: "João",
        //     lastName: "Pedro"
        // }
    }
}

Angular HTTP Client

A interface HttpClient do Angular é um serviço que facilita a comunicação com servidores HTTP, tornando a tarefa de fazer requisições HTTP mais simples e eficiente. Ele suporta métodos de requisição como GET, POST, PUT, DELETE, entre outros, e é baseado em Observables, permitindo o uso de operadores do RxJS para manipulação de dados e tratamento de erros.

Implementação

Importando o módulo HttpClientModule

Para utilizar o HttpClient, você precisa importá-lo no módulo principal da aplicação.

import { HttpClientModule } from "@angular/common/http";

@NgModule({
    imports: [HttpClientModule],
})
export class AppModule {}
Realizando Requisições HTTP
Requisição GET

Para realizar uma requisição GET, use o método HttpClient.get(). Este método retorna um Observable que emite os dados da resposta.

import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs";

@Injectable({
    providedIn: "root",
})
export class DataService {
    constructor(private http: HttpClient) {}

    getData(): Observable<MyDataType> {
        return this.http.get<MyDataType>("https://api.example.com/data");
    }
}
Requisição POST

Para enviar dados ao servidor, utilize o método HttpClient.post(). Este método aceita um objeto no corpo da requisição (payload) que será enviado ao servidor.

import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";

@Injectable({
    providedIn: "root",
})
export class DataService {
    constructor(private http: HttpClient) {}

    postData(data: MyDataType): Observable<MyDataType> {
        return this.http.post<MyDataType>("https://api.example.com/data", data);
    }
}
Configurando Cabeçalhos e Parâmetros

Você pode adicionar headers e parâmetros às suas requisições utilizando objetos de configuração.

Headers
import { HttpHeaders } from "@angular/common/http";

const headers = new HttpHeaders({
    "Content-Type": "application/json",
    Authorization: "Bearer my-token",
});

this.http.get<MyDataType>("https://api.example.com/data", { headers });
Parâmetros
import { HttpParams } from "@angular/common/http";

const params = new HttpParams().set("page", "1").set("pageSize", "10");

this.http.get<MyDataType>("https://api.example.com/data", { params });
Manipulação de Erros

Utilize operadores do RxJS para capturar e tratar erros em suas requisições.

import { catchError } from "rxjs/operators";
import { throwError } from "rxjs";

this.http
    .get<MyDataType>("https://api.example.com/data")
    .pipe(
        catchError((error) => {
            console.error("Erro na requisição", error);
            return throwError(error);
        })
    )
    .subscribe((data) => {
        // Processar os dados
    });
Manipulação de Eventos de Progresso

Você pode monitorar o progresso de uploads e downloads configurando a opção reportProgress.

this.http
    .post("https://api.example.com/upload", formData, {
        reportProgress: true,
        observe: "events",
    })
    .subscribe((event) => {
        if (event.type === HttpEventType.UploadProgress) {
            console.log(`Progresso: ${event.loaded} de ${event.total}`);
        } else if (event.type === HttpEventType.Response) {
            console.log("Upload completo!");
        }
    });
Exemplo Prático: Implementação de um serviço de usuários
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";

import { Observable } from "rxjs";

export interface User {
    id: number;
    name: string;
    email: string;
}

@Injectable({
    providedIn: "root",
})
export class UserService {
    private apiUrl = "https://api.example.com/users";

    constructor(private http: HttpClient) {}

    getUsers(): Observable<User[]> {
        return this.http.get<User[]>(this.apiUrl);
    }

    getUser(id: number): Observable<User> {
        return this.http.get<User>(`${this.apiUrl}/${id}`);
    }

    createUser(user: User): Observable<User> {
        return this.http.post<User>(this.apiUrl, user);
    }

    updateUser(id: number, user: User): Observable<User> {
        return this.http.put<User>(`${this.apiUrl}/${id}`, user);
    }

    deleteUser(id: number): Observable<void> {
        return this.http.delete<void>(`${this.apiUrl}/${id}`);
    }
}