Angular - alandrade21/docsCompartilhados GitHub Wiki

Nesta página:

  1. Instalação
  2. CLI
  3. View Elements
    1. Interpolation
    2. Input Property
    3. Eventos
    4. Template Reference
  4. Componentes
    1. Inputs para Componentes
    2. Eventos Emitidos por Componentes
  5. Core Directives
    1. ngFor
    2. ngIf
    3. ngClass
    4. ngStyle
    5. ngSwitch
    6. ng-container
  6. Pipes
  7. Services
    1. Async Pipe
    2. Serviços Customizados
  8. Módulos
  9. Router
    1. Setup Inicial

Instalação

O ecossistema para fazer o desenvolvimento de aplicações Angular envolve a instalação de 3 elementos distintos:

  • Uma versão do Angular, e seu cliente de linha de comando.
  • Uma versão do Typescript, e seu cliente de linha de comando.
  • Uma versão do NodeJs.

Cada versão de Angular tem restrições bem específicas sobre as versões de Typescript e de NodeJs que são necessárias para seu funcionamento.

Verifique a tabela de versões compatíveis.

Registrar a versão compatível do node no arquivo packages.json, através da entrada engines, conforme mostrado abaixo:

{
  ...
  "devDependencies": {
    "@angular/cli": "~1.7.3",
    ...
    "typescript": "~2.5.3"
    ...
  },
  "engines": {
    "node": "~8.9.4"
  },
  ...
}

Dessa forma, quem precisa evoluir ou manter várias aplicações Angular vai precisar, eventualmente, ter várias versões do Angular, do Typescript e do NodeJs em sua máquina, além de fazer o chaveamento entre essas versões.

  • Instalar nodeJs

Veja página específica.

  • Instala o angular cli localmente no projeto
npm i -D @angular/cli
  • Se der loop infinito, instala o node-gyp e tenta de novo
npm i -D node-gyp

Essa instalação coloca o angular cli na pasta node_modules/.bin do projeto. Para acessá-la sem ter que escrever todo o caminho, no arquivo package.json do projeto crie um script como o mostrado abaixo:

{
  ...
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
  ...
  }
}

Rode com npm run ng.

  • Instala o typescript

Veja página específica.

CLI

Digitar ng no terminal retorna uma página de ajuda.

  • ng generate component <<nome-componente>>: cria um novo componente no diretório atual ou caminho fornecido.
  • ng g directive <<nome-diretiva>>: cria uma nova diretiva no diretório atual ou caminho fornecido.
  • ng g service <<nome-serviço>>: cria novo serviço no diretório atual ou caminho fornecido.
  • ng g module <<nome-modulo>>: cria novo módulo no diretório atual ou caminho fornecido.

View Elements

Interpolation

Imprime dado do model na view. {{nome-variavel}}

Dentro da interpolação pode estar escrito qualquer código java script que será interpretado e o resultado será impresso na tela.

Interpolação não deixa injetar HTML nem script. Trata tudo como texto plano.

Input Property

Liga um campo da view com um dado da model. Two-way data binding.

<input [value]="data.title">

Esse exemplo liga o conteúdo da input ao campo title do objeto data da model. Qdo usa a sintaxe de colchetes no nome da propriedade, o conteúdo da propriedade é código js que será avaliado em tempo de execução.

Se quiser passar uma constante para a propriedade, faz assim: [value]="'texto plano'". Ou seja, coloca aspas simples dentro das aspas duplas. Isso é equivalente a não usar os colchetes.

Eventos

Liga um evento do browser a um código da model.

<img (click)="onLogoClicked()" ...>

O código acima chama o método onLogoClicked() da model no evento de click da imagem.

Template Reference

É possível dar nome a elementos do HTML.

<input #titleInput ...>

Agora esse input pode ser referenciado pelo nome titleInput. Por exemplo, titleInput.value retorna o conteúdo desse input. Template Reference aponta para o elemento do DOM que recebeu o nome.

Componentes

Cria um novo com o comando CLI ng generate component <<nome-componente>>. Cria no diretório atual.

Um componente é composto por um arquivo ts, um html e um css. No ts a classe é decorada com:

@Component({
    selector: '<<nome do seletor html onde o componente será plotado>>',
    templateURL: '<<caminho para o arquivo html com o html que será plotado no seletor>>',
    styleUrls: ['<<caminho para o arquivo css com os estilos usados no template do componente>>']
})

Inputs para Componentes

Para passar dados para um componente, no ts do componente deve haver uma variável para receber esse input decorada com @Input, por exemplo:

@Component({
    selector: 'course-card',
    templateURL: './course-card.component.html',
    styleUrls: ['./course-card.component.css']
})
export class CourseCardComponent implements OnInit {
    @Input()
    title: string;

    ...
}

O dado a ser passado para o componente aparece no seletor desse componente. Por exemplo:

<course-card [title]="Core Deep Dive"></course-card>

Eventos Emitidos por Componentes

Eventos de browser sobem pela árvore de componentes, mesmo tendo sido capturados em níveis mais baixos. Eventos customizados não.

Para disparar um evento customizado em um componente, primeiro é necessário definir o evento:

@Output()
courseSelected = new EventEmitter<Course>();

O evento deve ser decorado com @Output para que ele possa sair do componente. O evento é um objeto da classe EventEmitter do Angular, e o componente genérico é o elemento que será emitido no evento, no caso do exemplo, um objeto da classe Course.

Em algum lugar no código do componente, esse evento precisa ser disparado. Por exemplo:

onCourseViewed() {
    ...

    this.courseSelected.emit(this.course);

    ...
}

Esse tipo de evento é capturado no seletor do componente que o gera:

<course-card (courseSelected)="onCourseSelected($event)"></course-card>

No html, o elemento emitido é representado pelo $event.

O nome do evento customizado é o mesmo da variável que define o emitter. Para mudar, pode ser fornecido um novo nome no decorator @Output, assim: @Output('<<novo-nome>>').

Core Directives

ngFor

<course-card *ngFor="let course of courses; index as i; first; last; even; odd"
    [class.is-first]="first"
    [curso]="course" [cardIndex]="i + 1">
</course-card>

Courses é uma variável presente no componente ts.

Para publicar o índice para ser usado no html, basta colocar a variável index no ngFor. Ela pode ser renomeada com as alguma-coisa.

first é um booleano que informa se o elemento é o primeiro da interação. Usado para aplicar condicionalmente uma classe css. A sintaxe [class.is-first]= espera receber um booleano. No caso de true, aplica a classe ao elemento.

last, de forma similar, identifica o último elemento.

even e odd identificam se a interação é par ou ímpar.

ngIf

<img width="300" alt="Angular Logo" *ngIf="course.iconUrl"
    [src]="course.iconUrl">

Se o elemento avaliado resultar em undefined, a tag img não será montada no DOM da página resultante.

Casos de interpolation que usam atributos que podem ser nulos podem quebrar a carga de uma página. Um dos meios de evitar isso é utilizar o operador ?, conforme mostrado abaixo:

<div class="course-title">
    {{cardIndex + ' ' + course?.description}}
</div>

Outra forma de fazer a mesma coisa, impedindo que o operador ? apareça em vários lugares do template, é utilizar uma div externa que contenha toda a parte do template que dependa da propriedade que pode ser nula, e colocar um ngIf nessa diretiva:

<div class="course-card" *ngIf="course">

    <div class="course-title">
        {{cardIndex + ' ' + course.description}}
    </div>

    ...

</div>

É possível usar um else no ngIf:

<img width="300" alt="Angular Logo" *ngIf="course.iconUrl; else noImage"
    [src]="course.iconUrl">

<ng-template #noImage>
    <p>No image is available</p>
</ng-template>

ngClass

Usa para aplicar uma classe css de forma condicional.

.course-card.beginner {
    background: lightsalmon;
}

ngClass pode receber uma string contendo nomes de classes css, um array contendo strings com nomes de classes ou um objeto de configuração no formato {nomeClasse: booleano}. Faz o ngClass chamar um método que retorne algum desses elementos.

<div class="course-card" *ngIf="course" [ngClass]="cardClasses()">

    ...

</div>
cardClasses() {
    return {
        'beginner': this.course.category == 'BEGINNER'
    }
}

Outra maneira:

cardClasses() {

    if (this.course.category == 'BEGINNER')
    return 'beginner';
}

ngStyle

Usa para aplicar um estilo css de forma condicional.

Uma maneira de aplicar um estilo é:

<div class="course-title" [style.text-decoration]="'underline'">
    {{cardIndex + ' ' + course.description}}
</div>

Essa forma escreve direto no DOM HTML, e não utiliza uma diretiva angular.

ngStyle recebe um objeto de configuração:

<div class="course-title" [ngStyle]="{'text-decoration': 'underline'}">
    {{cardIndex + ' ' + course.description}}
</div>

Para fazer condicional, chama uma função:

<div class="course-title" [ngStyle]="cardStyles()">
    {{cardIndex + ' ' + course.description}}
</div>

ngSwitch

Para os casos em que a decisão condicional tem mais que duas opções.

<div class="course-category" [ngSwitch]="course.category">

    <div class="category" *ngSwitchCase="'BEGINNER'">Beginner</div>

    <div class="category" *ngSwitchCase="'INTERMEDIATE'">Intermediate</div>

    <div class="category" *ngSwitchCase="'ADVANCED'">Advanced</div>

    <div class="category" *ngSwitchDefault>All Levels</div>
</div>

ng-container

Quando não há uma tag que seja mãe de toda um estrutura que precisa ser acionada condicionalmente, é muito comum criar uma nova div mãe apenas para aplicar as diretivas que devem incidir sobre todas as tags filhas.

Ao invés de criar uma div, crie uma <ng-container></ng-container>. Essa diretiva tem a vantagem de não gerar elementos DOM adicionais.

Pipes

Funções de formatação de dados na tela.

<div>Start Date: {{startDate | date: 'dd/MM/yyyy'}}</div>

Se o pipe tiver vários argumentos, separa cada argumento com :.

Pipes: uppercase, lowercase, titlecase, number (: '3.3-5' -> 3 dígitos inteiros e no mínimo 3 e no máximo 5 casas decimais), currency (: 'EUR' -> Qual moeda utilizar), percent, slice (:0:2 -> faz um slice numa coleção, começando no elemento 0 e terminando no elemento 2, não inclusivo), json (imprime uma coleção na forma de um objeto json. Útil para debug), keyvalue (aplicado a um objeto, cria um array com todas as propriedades do objeto e seus valores).

<div *ngFor="let pair of course | keyvalue">
    {{pair.key + ': ' + pair.value}}
</div>

Services

Um serviço é injetado no construtor de um componente:

constructor(private http: HttpClient){}

Async Pipe

Serviços como HttpClient, geralmente retornam um Observable, que necessitam de um subscribe para terem seus dados acessados. A maneira mais fácil de fazer esse subscribe é definida abaixo:

courses$: Observable<Course[]>;

...

this.courses$ = this.http.get<Course[]>(...);

Na variável courses$, o $ indica que o conteúdo dessa variável é um observable. No template:

<course-card *ngFor="let course of (courses$ | async)">
</course-card>

O pipe async faz o subscribe e fornece os valores ao template. Outra opção com *ngIf:

<div *ngIf="(courses$ | async) as courses">
    <course-card *ngFor="let course of courses">
    </course-card>
</div>

A vantagem do uso de async pipe é que ele faz o unsubscribe do observable quando o componente é destruído, evitando memory leaks.

Serviços Customizados

A classe de serviço deve ser decorada com @Injectable.

@Injectable({
    providedIn: 'root'
})
export class CourseService {
    ...
}

Isso significa que será criado um singleton dessa classe e esse singleton estará disponível na raiz do sistema de injeção de dependências. A partir desse momento, essa classe pode ser injetada nos construtores dos componentes.

Se o providedIn não for informado, é necessário fornecer um provider ao componente que necessita ter o serviço injetado. Isso é feito no decorator @Component. Qdo um provider é fornecido a um componente, é criada uma instância da classe de serviço para cada instância do componente. Essa instância da classe de serviço está disponível para toda sub-árvore de componentes a partir do componente que recebeu o provider.

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls:['./app.component.css'],
    providers: [
        CourseService
    ]
})

Módulos

Unidade organizacional que agrupa componentes, diretivas, pipes e serviços.

Um módulo pode ser pulicado independente de uma aplicação.

@NgModule({
  declarations: [
    AppComponent,
    CourseCardComponent,
    CourseImageComponent,
    HighlightedDirective,
    NgxUnlessDirective
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

A seção declarations contém tudo o que foi construído dentro do módulo.

imports lista os módulos externos dos quais o código do módulo atual depende.

bootstrap identifica o componente que contém o seletor raiz a ser colocado no html, a partir do qual toda a árvore de componentes será montada.

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

    ...
}
<body>
    <app-root></app-root>
</body>

Se o index.html possuir mais de um seletor, então a seção bootstrap terá mais de um elemento.

Ao criar um módulo, é necessário dizer quais as partes desse módulo são visíveis fora dele. Para isso, é preciso colocar a propriedade exports: [] na @NgModule com os elementos da declarations: [] que são públicos.

Router

Setup Inicial

No index.html coloca a tag <case href="/">. Essa tag aponta para o ponto de entrada da aplicação.

Vai no AppModule (root module), e importa o router:

@NgModule({
  declarations: [
    App,
    LessonsList,
    CoursesList
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot(routeConfig)
  ],
  bootstrap: [App]
})
export class AppModule { }

Vai no html do componente raiz (App) e coloca <router-outlet></router-outlet> na posição da página onde os outlets das rotas devem ser injetados. Outlets são as seções que serão injetadas na página quando a rota mudar.

No arquivo router-config.ts é definido um array de rotas. Cada rota é um objeto contendo um path e um componente a ser inserido para aquela rota.

export const routeConfig = [
    {
        path: 'home',
        component: Home
    }
]
⚠️ **GitHub.com Fallback** ⚠️