<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Angular - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Aprenda a codificar - de graça. Tutoriais de programação em Python, JavaScript, Linux e muito mais. ]]>
        </description>
        <link>https://www.freecodecamp.org/portuguese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Angular - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/portuguese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 25 May 2026 04:46:52 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/portuguese/news/tag/angular/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Melhores práticas para uma aplicação em Angular limpa e de elevado desempenho ]]>
                </title>
                <description>
                    <![CDATA[ > Tradução em português europeu Escrito por: Vamsi Vempati Tenho vindo a trabalhar numa aplicação de grande escala em Angular na Trade Me [https://trademe.nz/], na Nova Zelândia, há um par de anos. Ao longo dos últimos anos, a nossa equipa tem vindo a refinar a nossa aplicação tanto em termos ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/melhores-praticas-para-uma-aplicacao-em-angular-limpa-e-de-elevado-desempenho/</link>
                <guid isPermaLink="false">65b8b4985afa84045c135536</guid>
                
                    <category>
                        <![CDATA[ Angular ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Afonso Branco ]]>
                </dc:creator>
                <pubDate>Wed, 12 Jun 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/0_q3-4kypImPD0VDPg.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/best-practices-for-a-clean-and-performant-angular-application-288e7b39eb6f/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Best practices for a clean and performant Angular application</a>
      </p><blockquote>Tradução em português europeu</blockquote><p>Escrito por: Vamsi Vempati</p><p>Tenho vindo a trabalhar numa aplicação de grande escala em Angular na <a href="https://trademe.nz/" rel="noopener">Trade Me</a>, na Nova Zelândia, há um par de anos. Ao longo dos últimos anos, a nossa equipa tem vindo a refinar a nossa aplicação tanto em termos de normas de programação como em desempenho, para que esteja no melhor estado possível.</p><p>Este artigo descreve as práticas que utilizamos na nossa aplicação e está relacionado com Angular, Typescript, RxJs e @ngrx/store. Também vamos abordar algumas diretrizes gerais de programação para ajudar a aplicação a ficar mais limpa.</p><h4 id="1-trackby"><strong><strong><strong>1) trackBy</strong></strong></strong></h4><p>Ao utilizar <code>ngFor</code> para iterar sobre um <em>array </em>em <em>templates</em>, utiliza-o com uma função <code>trackBy</code>, que retornará um identificador único por cada item.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Quando um <em>array</em> muda, o Angular renderiza novamente toda a árvore do DOM. Se, no entanto, utilizares <code>trackBy</code>, o Angular saberá que elemento foi alterado e realizará alterações à árvore do DOM apenas para esse elemento em particular.</p><p>Para uma explicação detalhada sobre isso, consulta <a href="https://netbasal.com/angular-2-improve-performance-with-trackby-cc147b5104e5" rel="noopener">este artigo</a> por Netanel Basal (em inglês).</p><p><strong>Antes</strong></p><pre><code class="language-ts">&lt;li *ngFor="let item of items;"&gt;{{ item }}&lt;/li&gt;</code></pre><p><strong>Depois</strong></p><pre><code class="language-ts">// no template

&lt;li *ngFor="let item of items; trackBy: trackByFn"&gt;{{ item }}&lt;/li&gt;

// no componente

trackByFn(index, item) {    
   return item.id; // correspondência de id único do item
}</code></pre><h4 id="2-const-x-let"><strong><strong><strong>2) const </strong></strong>x<strong><strong> let</strong></strong></strong></h4><p>Ao declarar variáveis, utiliza const nos casos em que o valor não será redefinido.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Utilizar <code>let</code> e <code>const</code> quando for adequado clarifica a intenção das declarações. Também ajudará a identificar problemas quando um valor é acidentalmente reatribuído a uma constante, ao gerar um erro de compilação. Também ajuda a melhorar a legibilidade do código.</p><p><strong>Antes</strong></p><pre><code class="language-ts">let car = 'ludicrous car';

let myCar = `My ${car}`;
let yourCar = `Your ${car};

if (iHaveMoreThanOneCar) {
   myCar = `${myCar}s`;
}

if (youHaveMoreThanOneCar) {
   yourCar = `${youCar}s`;
}</code></pre><p><strong>Depois</strong></p><pre><code class="language-ts">// o valor de car não é redefinido, por isso podemos torná-lo numa const
const car = 'ludicrous car';

let myCar = `My ${car}`;
let yourCar = `Your ${car};

if (iHaveMoreThanOneCar) {
   myCar = `${myCar}s`;
}

if (youHaveMoreThanOneCar) {
   yourCar = `${youCar}s`;
}</code></pre><h4 id="3-operadores-canaliz-veis"><strong>3) Operadores canalizáveis</strong></h4><p>Utiliza operadores canalizáveis ao utilizar operadores RxJs.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Os operadores canalizáveis são "<em>tree-shakeable</em>", o que significa que apenas o código de cuja execução precisamos será incluído quando os operadores são importados.</p><p>Isso também faz com que seja mais fácil identificar operadores inutilizados nos ficheiros.</p><p><em><em>Not</em>a<em>:</em></em> isso requer a versão 5.5+ do Angular.</p><p><strong>Antes</strong></p><pre><code class="language-ts">import 'rxjs/add/operator/map';
import 'rxjs/add/operator/take';

iAmAnObservable
    .map(value =&gt; value.item)
    .take(1);</code></pre><p><strong>Depois</strong></p><pre><code class="language-ts">import { map, take } from 'rxjs/operators';

iAmAnObservable
    .pipe(
       map(value =&gt; value.item),
       take(1)
     );</code></pre><h4 id="4-truques-isolados-de-api"><strong>4) Truques isolados de API</strong></h4><p>Nem todas as APIs são à prova de bala — por vezes, precisamos de adicionar alguma lógica no código para compensar os erros nas APIs. Em vez de ter os truques em componentes onde eles são necessários, é melhor isolá-los num local — como, por exemplo, um serviço e utilizar o servido a partir do componente.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Isso ajuda a manter os truques "mais próximos da API", ou seja, tão próximo do local onde o pedido de rede é realizado quanto possível. Desse modo, existe menos código a lidar com erros. Além disso, existe um local onde residem todos os truques e é mais fácil encontrá-los. Ao corrigir erros nas APIs, é mais fácil procurar os truques num ficheiro, em vez de procurar os truques que poderiam estar espalhados pela base de código.</p><p>Também podes criar tags personalizadas, como API_FIX, semelhante a TODO e anexar as correções à tag para que seja mais fácil de encontrar.</p><h4 id="5-subscrever-em-template"><strong>5) Subscrever em <em>template</em></strong></h4><p>Evita subscrever a observáveis a partir de componente. Em vez disso, subscreve aos observáveis a partir do <em>template</em>.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Os canais <code>async</code> removem a sua subscrição automaticamente e tornam o código mais simples ao eliminar a necessidade de gerir manualmente subscrições. Também reduz o risco de acidentalmente esquecer a remoção da subscrição no componente, que causaria uma fuga de memória. Esse risco também pode ser mitigado ao utilizar uma regra de <em>lint</em> para detetar observáveis não subscritos.</p><p>Isto também impede que os componentes tenham estado e introduzam erros onde os dados são alterados fora da subscrição.</p><p><strong>Antes</strong></p><pre><code>// template

&lt;p&gt;{{ textToDisplay }}&lt;/p&gt;

// componente

iAmAnObservable
    .pipe(
       map(value =&gt; value.item),
       takeUntil(this._destroyed$)
     )
    .subscribe(item =&gt; this.textToDisplay = item);</code></pre><p><strong>Depois</strong></p><pre><code class="language-ts">// template

&lt;p&gt;{{ textToDisplay$ | async }}&lt;/p&gt;

// componente

this.textToDisplay$ = iAmAnObservable
    .pipe(
       map(value =&gt; value.item)
     );</code></pre><h4 id="6-limpar-subscri-es"><strong><strong><strong>6) </strong></strong>Limpar subscrições</strong></h4><p>Ao fazer subscrição a observáveis, certifica-te sempre que removes a subscrição a eles adequadamente ao utilizar operadores como <code>take</code>, <code>takeUntil</code> etc.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Não remover a subscrição a observáveis causará fugas de memória indesejáveis, pois o fluxo de observáveis é deixado aberto, potencialmente, até mesmo após a destruição de um componente/o utilizador ter navegado para outra página.</p><p>Melhor ainda, cria uma regra <em>lint</em> para detetar observáveis cuja subscrição não tenha sido removida.</p><p><strong>Antes</strong></p><pre><code>iAmAnObservable
    .pipe(
       map(value =&gt; value.item)     
     )
    .subscribe(item =&gt; this.textToDisplay = item);</code></pre><p><strong>Depois</strong></p><p>Utilizar <code>takeUntil</code> quando desejas aguardar por alterações até que outro observável emita um valor:</p><pre><code>private _destroyed$ = new Subject();

public ngOnInit (): void {
    iAmAnObservable
    .pipe(
       map(value =&gt; value.item)
      // Queremos aguardar por iAmAnObservable até que o componente seja destruído,
       takeUntil(this._destroyed$)
     )
    .subscribe(item =&gt; this.textToDisplay = item);
}

public ngOnDestroy (): void {
    this._destroyed$.next();
    this._destroyed$.complete();
}</code></pre><p>Utilizar um sujeito privado como esse é um padrão para gerir a remoção da subscrição de vários observáveis no componente.</p><p>Utilizar <code>take</code> quando queres apenas o primeiro valor emitido pelo observável:</p><pre><code class="language-ts">iAmAnObservable
    .pipe(
       map(value =&gt; value.item),
       take(1),
       takeUntil(this._destroyed$)
    )
    .subscribe(item =&gt; this.textToDisplay = item);</code></pre><p>Observa aqui a utilização de <code>takeUntil</code> com <code>take</code>. Isso é para evitar fugas de memória quando a subscrição não tiver recebido um valor antes do componente ter sido destruído. Sem <code>takeUntil</code> aqui, a subscrição ainda permaneceria até obter o primeiro valor, mas visto que o componente já foi destruído, ele nunca obterá um valor — levando a uma fuga de memória.</p><h4 id="7-utilizar-operadores-apropriados"><strong>7) Utilizar operadores apropriados</strong></h4><p>Ao utilizar operadores de <em>flattening</em> com os teus observáveis, utiliza o operador adequado para a situação.</p><p><em><em>switchMap:</em></em> quando desejas ignorar as emissões anteriores quando existe uma nova emissão.</p><p><em><em>mergeMap:</em></em> quando desejas lidar simultaneamente com todas as emissões.</p><p><em><em>concatMap:</em></em> quando desejas lidar com as emissões uma após a outra, à medida que são emitidas.</p><p><em><em>exhaustMap: </em></em>quando desejas cancelar todas as emissões novas enquanto processas a emissão anterior.</p><p>Para uma explicação detalhada disso, observa <a href="https://blog.angularindepth.com/switchmap-bugs-b6de69155524" rel="noopener">este</a> artigo de Nicholas Jamieson (em inglês).</p><p><strong>Por quê<strong>?</strong></strong></p><p>Utilizar um único operador quando possível, em vez de encadear vários outros operadores para alcançar o mesmo efeito, pode fazer com que seja enviado menos código para o <em>client</em>. Utilizar os operadores errados pode levar a comportamentos indesejados, visto que operadores diferentes lidam com observáveis de maneiras diferentes.</p><h4 id="8-carregamento-lento-lazy-loading-"><strong>8) Carregamento lento (<em>lazy loading</em>)</strong></h4><p>Quando possível, tenta carregar lentamente os módulos na tua aplicação em Angular. Carregamento lento é quando carregas algo apenas quando é utilizado – por exemplo, carregar um componente apenas quando ele tiver de ser visto.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Isso reduzirá o tamanho da aplicação a ser carregada e pode melhorar o tempo de iniciação da aplicação ao não carregar os módulos que não são utilizados.</p><p><strong>Antes</strong></p><pre><code>// app.routing.ts

{ path: 'not-lazy-loaded', component: NotLazyLoadedComponent }</code></pre><p><strong>Depois</strong></p><pre><code class="language-ts">// app.routing.ts

{ 
  path: 'lazy-load',
  loadChildren: 'lazy-load.module#LazyLoadModule' 
}

// lazy-load.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { LazyLoadComponent }   from './lazy-load.component';

@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild([
         { 
             path: '',
             component: LazyLoadComponent 
         }
    ])
  ],
  declarations: [
    LazyLoadComponent
  ]
})
export class LazyModule {}</code></pre><h4 id="9-evitar-ter-subscri-es-dentro-de-subscri-es"><strong>9) Evitar ter subscrições dentro de subscrições</strong></h4><p>Por vezes, podes querer que os valores de mais do que um observável realizem uma ação. Nesse caso, evita subscrever um observável no bloco de subscrição de outro observável. Em vez disso, utiliza operadores de encadeamento adequados. Os operadores de encadeamento correm nos observáveis do operador antes deles. Alguns operadores são: <code>withLatestFrom</code>, <code>combineLatest</code> etc.</p><p><strong>Antes</strong></p><pre><code>firstObservable$.pipe(
   take(1)
)
.subscribe(firstValue =&gt; {
    secondObservable$.pipe(
        take(1)
    )
    .subscribe(secondValue =&gt; {
        console.log(`Os valores combinados são: ${firstValue} e ${secondValue}`);
    });
});</code></pre><p><strong>Depois</strong></p><pre><code class="language-ts">firstObservable$.pipe(
    withLatestFrom(secondObservable$),
    first()
)
.subscribe(([firstValue, secondValue]) =&gt; {
    console.log(`Os valores combinados são: ${firstValue} e ${secondValue}`);
});</code></pre><p><strong>Por quê<strong>?</strong></strong></p><p><em>"<em>Code smell</em>"<em>/</em>legibilidade<em>/complexi</em>dade</em>: não utilizar RxJs em toda a sua extensão, sugere que o programador não está familiarizado com a área de superfície da API RxJs API.</p><p><em>Desempenho</em>: se os observáveis estiverem inativos, o código subscreverá para firstObservable, esperará que ele termine e DEPOIS iniciará o trabalho com o segundo observável. Se esses fossem pedidos de rede, seria mostrado como assíncrono/cascata.</p><h4 id="10-evitar-any-e-atribuir-tipo-a-tudo"><strong>10) Evitar "any" e atribuir tipo a tudo</strong></h4><p>Declara sempre variáveis ou constantes com um tipo diferente de <code>any</code>.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Ao declarar variáveis ou constantes em Typescript sem uma tipologia, o tipo da variável/constante será deduzido pelo valor que lhe é atribuído. Isso causará problemas não pretendidos. Um exemplo clássico é:</p><pre><code>const x = 1;
const y = 'a';
const z = x + y;

console.log(`O valor de z é: ${z}`

// Resultado
O valor de z é 1a</code></pre><p>Isso pode causar problemas indesejados quando esperas que y também seja um número. Esses problemas podem ser evitados ao escrever as variáveis de maneira apropriada.</p><pre><code>const x: number = 1;
const y: number = 'a';
const z: number = x + y;

// Isto gerará um erro de compilação a dizer:

Type '"a"' is not assignable to type 'number'.

const y:number</code></pre><p>Dessa forma, podemos evitar erros causados pela ausência de tipos.</p><p>Outra vantagem de ter boas tipologias na tua aplicação é que torna a refatorização mais fácil e segura.</p><p>Considera estes exemplos:</p><pre><code>public ngOnInit (): void {
    let myFlashObject = {
        name: 'My cool name',
        age: 'My cool age',
        loc: 'My cool location'
    }
    this.processObject(myFlashObject);
}

public processObject(myObject: any): void {
    console.log(`Name: ${myObject.name}`);
    console.log(`Age: ${myObject.age}`);
    console.log(`Location: ${myObject.loc}`);
}

// Resultado
Name: My cool name
Age: My cool age
Location: My cool location</code></pre><p>Digamos que queremos renomear a propriedade &nbsp;<code>loc</code> para <code>location</code> em <code>myFlashObject</code>:</p><pre><code>public ngOnInit (): void {
    let myFlashObject = {
        name: 'My cool name',
        age: 'My cool age',
        location: 'My cool location'
    }
    this.processObject(myFlashObject);
}

public processObject(myObject: any): void {
    console.log(`Name: ${myObject.name}`);
    console.log(`Age: ${myObject.age}`);
    console.log(`Location: ${myObject.loc}`);
}

// Resultado
Name: My cool name
Age: My cool age
Location: undefined</code></pre><p>Se não tivermos um tipo no <code>myFlashObject</code>, este pensará que a propriedade <code>loc</code> em <code>myFlashObject</code> é apenas indefinida, em vez de não ser uma propriedade válida.</p><p>Se tivéssemos um tipo para <code>myFlashObject</code>, obteríamos um bom erro de tempo de compilação como mostrado abaixo:</p><pre><code>type FlashObject = {
    name: string,
    age: string,
    location: string
}

public ngOnInit (): void {
    let myFlashObject: FlashObject = {
        name: 'My cool name',
        age: 'My cool age',
        // Erro de compilação
        Type '{ name: string; age: string; loc: string; }' is not assignable to type 'FlashObjectType'.
        Object literal may only specify known properties, and 'loc' does not exist in type 'FlashObjectType'.
        loc: 'My cool location'
    }
    this.processObject(myFlashObject);
}

public processObject(myObject: FlashObject): void {
    console.log(`Name: ${myObject.name}`);
    console.log(`Age: ${myObject.age}`)
    // Erro de compilação
    Property 'loc' does not exist on type 'FlashObjectType'.
    console.log(`Location: ${myObject.loc}`);
}</code></pre><p>Se estiveres a iniciar um novo projeto, vale a pena definir <code>strict:true</code> no ficheiro <code>tsconfig.json</code> para ativar todas as opções rigorosas de verificação de tipo.</p><h4 id="11-faz-uso-das-regras-de-lint"><strong>11) Faz uso das regras de <em>lint</em></strong></h4><p>O <a href="https://palantir.github.io/tslint/" rel="noopener"><code>tslint</code></a> tem várias opções já incorporadas como <a href="https://palantir.github.io/tslint/rules/no-any" rel="noopener"><code>no-any</code></a>, <a href="https://palantir.github.io/tslint/rules/no-magic-numbers" rel="noopener"><code>no-magic-numbers</code></a>, <a href="https://palantir.github.io/tslint/rules/no-console" rel="noopener"><code>no-console</code></a> etc, que podes configurar no teu <code>tslint.json</code> para impor certas regras na tua base de código.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Ter regras de <em>lint</em> aplicadas significa que obterás um erro útil caso estejas a fazer algo que não deverias estar a fazer. Isso garantirá consistência e legibilidade. Por favor, consulta <a href="https://palantir.github.io/tslint/rules/" rel="noopener">aqui</a> (em inglês) mais regras que podes configurar.</p><p>Alguma regras de <em>lint</em> até têm correções para resolver o erro de <em>lint</em>. Se desejares configurar a tua própria regra de <em>lint</em> personalizada, também podes fazê-lo. Consulta, por favor, <a href="https://medium.com/@phenomnominal/custom-typescript-lint-rules-with-tsquery-and-tslint-144184b6ff2d" rel="noopener">este artigo</a> de Craig Spence (em inglês) sobre como escrever as tuas próprias regras de <em>lint</em> personalizadas utilizando o <a href="https://github.com/phenomnomnominal/tsquery" rel="noopener">TSQuery</a>.</p><p><strong>Antes</strong></p><pre><code>public ngOnInit (): void {
    console.log('Eu sou uma mensagem do console');
    console.warn('Eu sou uma mensagem de aviso do console');
    console.error('Eu sou uma mensagem de erro do console');
}

// Resultado - sem erros, imprimirá o que vemos abaixo na janela do console:
Eu sou uma mensagem do console
Eu sou uma mensagem de aviso do console
Eu sou uma mensagem de erro do console</code></pre><p><strong>Depois</strong></p><pre><code>// tslint.json
{
    "rules": {
        .......
        "no-console": [
             true,
             "log",    // console.log não é permitido
             "warn"    // console.warn não é permitido
        ]
   }
}

// ..component.ts

public ngOnInit (): void {
    console.log('Eu sou uma mensagem do console');
    console.warn('Eu sou uma mensagem de aviso do console');
    console.error('Eu sou uma mensagem de erro do console');
}

// Resultado - erros de lint para as instruções de console.log e console.warn, mas sem erro para console.error, já que não foi mencionado no config

Calls to 'console.log' are not allowed.
Calls to 'console.warn' are not allowed.</code></pre><h4 id="12-pequenos-componentes-reutiliz-veis"><strong>12) Pequenos componentes reutilizáveis</strong></h4><p>Extrai as partes que podem ser reutilizadas num componente e cria outro. Torna o componente tão "burro" quanto possível, visto que isso fará com que funcione em mais cenários. Tornar um componente "burro" quer dizer que o componente não tem nenhuma lógica em especial e opera puramente com base nos <em>inputs</em> e <em>outputs</em> que lhe forem fornecidos.</p><p>Como regra geral, o último descendente na árvore de componentes será o mais burro de todos.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Os componentes reutilizáveis reduzem a repetição de código, tornando-o assim mais fácil de gerir e de receber alterações.</p><p>Os componentes "burros" são mais simples e, por isso, têm menos probabilidade de terem erros. Os componentes "burros" fazem-te pensar mais sobre a API de componente pública e ajudam-te a detetar preocupações contraditórias.</p><h4 id="13-os-componentes-devem-lidar-apenas-com-l-gica-de-exibi-o"><strong>13) Os componentes devem lidar apenas com lógica de exibição</strong></h4><p>Evita ter qualquer outra lógica para além da lógica de exibição no teu componente sempre que puderes e faz com que o componente lide apenas com a lógica de exibição.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Os componentes são projetados para fins de exibição e controlam o que a vista deve fazer. Qualquer lógica empresarial deve ser extraída nos seus próprios métodos/serviços, onde for apropriado, separando a lógica empresarial da lógica de exibição.</p><p>A lógica empresarial é geralmente mais fácil de testar quando é extraída para um serviço. Ela pode ser reutilizada por quaisquer outros componentes que precisem da mesma lógica empresarial aplicada.</p><h4 id="14-evita-m-todos-longos"><strong>14) Evita métodos longos</strong></h4><p>Métodos longos geralmente indicam que estão a fazer muitas coisas. Tenta utilizar o Princípio de Responsabilidade Única. O método por si só pode estar a fazer uma coisa, mas, dentro dele, existem algumas operações que podem estar a acontecer. Podemos extrair esses métodos para o seu próprio método e fazer com que façam cada um uma coisa e utilizá-los.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Os métodos longos são difíceis de ler, compreender e manter. Também são susceptíveis a erros, visto que alterar uma coisa pode afetar diversas outras coisas nesse método. Também tornam a refatorização (que é uma coisa essencial em qualquer aplicação) difícil.</p><p>Isso é por vezes medido como "<a href="https://pt.wikipedia.org/wiki/Complexidade_ciclom%C3%A1tica">complexidade ciclomática</a>". Também existem algumas <a href="https://www.npmjs.com/package/tslint-sonarts" rel="noopener">regras do TSLint</a> para detetar complexidade ciclomática/cognitiva, que podes utilizar no teu projeto para evitar erros e detetar "<em>code smells</em>" e problemas de manutenção.</p><h4 id="15-dry-n-o-te-repitas-"><strong>15) DRY (Não te repitas)</strong></h4><p><em>Do not Repeat Yourself</em> (Não te repitas). Certifica-te de que não tens o mesmo código copiado para locais diferentes na base de código. Extrai o código repetido e utiliza isso em vez do código repetido.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Ter o mesmo código em vários locais significa que, se quisermos fazer uma alteração à lógica nesse código, temos de fazê-la em vários locais. Isso torna-o difícil de gerir e também é susceptível a erros. Podemos falhar e não alterar em todas as ocorrências. É mais demorado realizar alterações à lógica e testar o código também é um processo demorado.</p><p>Nesses casos, extrai o código repetido e utiliza essa alternativa em vez disso. Isso quer dizer que existe apenas um local para alterar e uma coisa para testar. Ter menos código duplicado enviado para os utilizadores quer dizer que a aplicação será mais rápida.</p><h4 id="16-adicionar-mecanismos-de-cache"><strong>16) Adicionar mecanismos de cache</strong></h4><p>Ao realizar chamadas de API, as respostas delas não mudam com frequência. Nesses casos, podes adicionar um mecanismo de cache e armazenar o valor da API. Quando for realizado outro pedido à mesma API, verifica se existe um valor para ele na cache. Caso exista, utiliza-o. Caso contrário, realiza a chamada da API e coloca o resultado em cache.</p><p>Se os valores alterarem, mas não regularmente, podes introduzir uma cache de tempo onde podes verificar quando foi colocado algo em cache pela última vez e decidir se chamas ou não a API.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Ter um mecanismo de cache significa evitar chamadas de API indesejadas. Ao realizar apenas as chamadas de API quando necessário e evitar código duplicado, a velocidade da aplicação melhora pois não temos de esperar pela rede. Também significa que não descarregamos a mesma informação vezes sem conta.</p><h4 id="17-evitar-l-gica-em-templates"><strong>17) Evitar lógica em <em>templates</em></strong></h4><p>Se tiveres qualquer tipo de lógica nos teus <em>templates</em>, mesmo que seja uma simples cláusula <code>&amp;&amp;</code>, é bom extraí-la para o seu próprio componente.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Ter lógica no <em>template </em>significa que não é possível realizar testes unitários ao <em>template</em> e é, então, mais susceptível a erros quando alteramos o código do <em>template</em>.</p><p><strong>Antes</strong></p><pre><code>// template
&lt;p *ngIf="role==='developer'"&gt; Status: Developer &lt;/p&gt;

// component
public ngOnInit (): void {
    this.role = 'developer';
}</code></pre><p><strong>Depois</strong></p><pre><code class="language-ts">// template
&lt;p *ngIf="showDeveloperStatus"&gt; Status: Developer &lt;/p&gt;

// componente
public ngOnInit (): void {
    this.role = 'developer';
    this.showDeveloperStatus = true;
}</code></pre><h4 id="18-strings-devem-ser-seguras"><strong>18) Strings devem ser seguras</strong></h4><p>Se tiveres uma variável do tipo string que possa ter apenas um conjunto de valores, em vez de declará-la com o tipo string, podes declarar a lista de valores possíveis como o tipo.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Ao declarar o tipo da variável adequadamente, podemos evitar erros ao escrever o código durante a compilação em vez de durante a execução.</p><p><strong>Antes</strong></p><pre><code>private myStringValue: string;

if (itShouldHaveFirstValue) {
   myStringValue = 'First';
} else {
   myStringValue = 'Second'
}</code></pre><p><strong>Depois</strong></p><pre><code class="language-ts">private myStringValue: 'First' | 'Second';

if (itShouldHaveFirstValue) {
   myStringValue = 'First';
} else {
   myStringValue = 'Other'
}

// Isso gerará o erro abaixo
Type '"Other"' is not assignable to type '"First" | "Second"'
(property) AppComponent.myValue: "First" | "Second"</code></pre><h3 id="vis-o-geral"><strong>Visão geral</strong></h3><h4 id="gest-o-de-estado"><strong>Gestão de estado</strong></h4><p>Considera utilizar <a href="https://github.com/ngrx/platform" rel="noopener">@ngrx/store</a> para gerir o estado da tua aplicação e <a href="https://github.com/ngrx/effects" rel="noopener">@ngrx/effects</a> como modelo de efeito secundário para armazenamento. As alterações de estados são descritas pelas ações e as alterações são realizadas por funções puras chamadas <em>reducers</em>(redutores).</p><p><strong>Por quê<strong>?</strong></strong></p><p><em><em>@ngrx/store</em></em> isola toda a lógica relacionada com estados num só local e torna-a consistente ao longo da aplicação. Também tem um mecanismo de memorização ao aceder à informação armazenada, levando a uma aplicação com melhor desempenho. <em><em>@ngrx/store </em></em>combinado com a estratégia de deteção de alterações do Angular resulta numa aplicação mais rápida.</p><h4 id="estado-imut-vel"><strong>Estado imutável</strong></h4><p>Ao utilizar <em><em>@ngrx/store</em></em>, considera utilizar <a href="https://github.com/brandonroberts/ngrx-store-freeze" rel="noopener">ngrx-store-freeze</a> para tornar o estado imutável. <em><em>ngrx-store-freeze</em></em> impede que o estado seja alterado ao lançar uma excepção. Isso evita alterações acidentais do estado, o que leva a consequências indesejadas.</p><p><strong>Por quê<strong>?</strong></strong></p><p>Alterar o estado em componentes faz com que a aplicação se comporte de modo inconsistente com base na ordem de carregamento dos componentes. Quebra o modelo mental do padrão <em>redux</em>. As alterações podem acabar sobrepostas caso o estado de armazenamento altere e seja emitido novamente. Separa as responsabilidades/preocupações — componentes são camadas de vista, não devem saber como alterar o estado.</p><h4 id="jest"><strong>Jest</strong></h4><p>O <a href="https://jestjs.io/" rel="noopener">Jest</a> é uma <em>framework </em>de testes unitários da Facebook para JavaScript. Torna os testes unitários mais rápidos ao colocar em paralelo as execuções de testes ao longo da base de código. Com o seu modo de observação, são executados apenas os testes relacionados com as alterações, o que torna o ciclo de resposta para os testes muito mais curto. Ele<em><em> </em></em>também fornece cobertura de código dos testes e é suportado no VS Code e Webstorm.</p><p>Podias utilizar um <a href="https://github.com/thymikee/jest-preset-angular" rel="noopener">preset</a> (texto em inglês) para Jest que fará a maior parte do trabalho por ti quando estiveres a configurar a Jest no teu projeto.</p><h4 id="karma"><strong>Karma</strong></h4><p><a href="https://karma-runner.github.io/2.0/index.html" rel="noopener">Karma</a> é um executante de testes desenvolvido pela equipa do AngularJS. Este requer um <em>browser</em> real/DOM para executar os testes. Também pode ser executado em <em>browsers</em> diferentes. O Jest não precisa do Chrome headless/phantomjs para executar os testes e é executado em Node puro.</p><h4 id="universal"><strong>Universal</strong></h4><p>Se não tiveres tornado a tua aplicação numa aplicação <em><em>Universal</em></em>, agora é uma boa altura para fazê-lo. O <a href="https://angular.io/guide/universal" rel="noopener">Angular Universal</a> (link em inglês) permite-te executar a tua aplicação do Angular no servidor e faz renderização no lado do servidor (SSR), que serve páginas html estáticas pré-renderizadas. Isso torna a aplicação muito rápida, pois apresenta o conteúdo no ecrã quase instantaneamente, sem ter de esperar que os JS <em>bundles</em> carreguem e analisem, ou pela iniciação do Angular.</p><p>Também é bom em termos de SEO, visto que o Angular Universal gera conteúdo estático e torna mais fácil a indexação da aplicação por parte dos rastreadores da web e tornam a aplicação pesquisável sem executar JavaScript.</p><p><strong>Por quê<strong>?</strong></strong></p><p>O Universal melhora drasticamente o desempenho da tua aplicação. Atualizamos recentemente a nossa aplicação para realizar renderização do lado do servidor e o tempo de carregamento do site passou de vários segundos para dezenas de milésimos de segundo!</p><p>Também permite que o teu site apareça corretamente nos modelos de pré-visualização das redes sociais. O primeiro carregamento significativo é muito rápido e torna o conteúdo visível aos utilizadores sem quaisquer atrasos indesejados.</p><h3 id="conclus-o"><strong>Conclusão</strong></h3><p>Criar aplicações é uma jornada constante e existe sempre espaço para melhorar coisas. Esta lista de optimizações é um bom local para começar, e aplicar de maneira consistente esses padrões fará a tua equipa feliz. Os teus utilizadores também vão adorar-te pela boa experiência na tua aplicação com menos problemas e com melhor desempenho.</p><p><em>Obrigada pela leitura<em>! </em>Se gostaste deste artigo<em>, </em>fica à vontade para partilhar e ajudar outras pessoas a encontrá-lo<em>. </em>Segue a autora no<em> </em></em><a href="https://medium.com/@vamsivempati"><em><em>Medium</em></em></a><em><em> o</em>u<em> </em></em><a href="https://twitter.com/_VamsiVempati_"><em><em>Twitter</em></em></a><em><em> </em>para ver mais artigos<em>. </em>Boa programação, pessoal<em>!</em></em> ☕️</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como validar formulários do Angular orientados a templates ]]>
                </title>
                <description>
                    <![CDATA[ Introdução Neste artigo, aprenderemos sobre validações em formulários do Angular orientados a templates. Criaremos um formulário simples de registro de usuário e implementaremos algumas validações embutidas nele. Junto às validações embutidas, implementaremos algumas validações customizadas para o formulário orientado a templates. Consideraremos as seguintes validações customizadas para essa demonstração:  ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-validar-formularios-do-angular-orientados-a-templates/</link>
                <guid isPermaLink="false">64d62fa5802b5c066d51abd5</guid>
                
                    <category>
                        <![CDATA[ Angular ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Luiz Nison Filler ]]>
                </dc:creator>
                <pubDate>Thu, 05 Oct 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/10/5f9c9e88740569d1a4ca3da3.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-validate-angular-template-driven-forms/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Validate Angular Template-Driven Forms</a>
      </p><h2 id="introdu-o"><strong><strong>Introdução</strong></strong></h2><p>Neste artigo, aprenderemos sobre validações em formulários do Angular orientados a <em>templates</em>. Criaremos um formulário simples de registro de usuário e implementaremos algumas validações embutidas nele. Junto às validações embutidas, implementaremos algumas validações customizadas para o formulário orientado a templates.</p><p>Consideraremos as seguintes validações customizadas para essa demonstração:</p><ul><li>Verificação de disponibilidade do nome de usuário;</li><li>Validação de padrão de senha;</li><li>Correspondência da senha inserida em dois campos diferentes.</li></ul><p>Dê uma olhada na aplicação funcionando:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/10/TemplateFormValidation.gif" class="kg-image" alt="TemplateFormValidation" width="650" height="648" loading="lazy"></figure><h2 id="pr-requisitos"><strong><strong><strong><strong>Pr</strong></strong></strong>é-requisitos</strong></h2><ul><li>Instale o Visual Studio Code <a href="https://code.visualstudio.com/" rel="noreferrer noopener">aqui</a>;</li><li>Instale a última versão da Angular CLI por <a href="https://cli.angular.io/" rel="noreferrer noopener">aqui</a>;</li><li>Instale a última versão LTS do Node.js <a href="https://nodejs.org/pt-br/">aqui</a>.</li></ul><h2 id="c-digo-fonte"><strong>Código fonte</strong></h2><p>Você pode acessar o código fonte pelo <a href="https://github.com/AnkitSharma-007/angular-forms-validation" rel="noreferrer noopener">GitHub</a>.</p><h2 id="crie-a-aplica-o-do-angular"><strong>Crie a aplicação do <strong><strong><strong>Angular</strong></strong></strong></strong></h2><p>Navegue até o diretório no qual deseja criar o seu projeto. Abra uma janela de comando e execute o comando mostrado abaixo: &nbsp;</p><pre><code>ng new angular-forms-validation --routing=false --style=scss</code></pre><p>Estamos especificando o comando para criar uma aplicação do Angular. A opção para criar o módulo de roteamento é definida como <code>false</code> e a extensão de arquivos de estilização é definida como SCSS. Esse comando criará o projeto do Angular com o nome <code>angular-forms-validation</code>.</p><p>Dirija-se ao diretório do novo projeto e abra-o no VS Code usando o conjunto de comandos abaixo.</p><pre><code>cd angular-forms-validation
code .</code></pre><h2 id="instale-o-bootstrap"><strong>Instale<strong> </strong>o <strong>Bootstrap</strong></strong></h2><p>Execute o seguinte comando para instalar o Bootstrap:</p><pre><code>npm install bootstrap --save</code></pre><p>Adicione a seguinte definição de importação no arquivo <code>styles.scss</code> :</p><pre><code>@import "~bootstrap/dist/css/bootstrap.css";</code></pre><h2 id="crie-o-servi-o-de-valida-o"><strong>Crie o serviço de validação</strong></h2><p>Execute o seguinte comando para criar um serviço:</p><pre><code>ng g s services\customvalidation</code></pre><p>Esse comando criará um subdiretório chamado <code>services</code>, que possui dois arquivos dentro dele – <code>customvalidation.service.ts</code> e <code>customvalidation.service.spec.ts</code>. Abra <code>customvalidation.service.ts</code> e insira o seguinte código dentro dele.</p><pre><code>import { Injectable } from '@angular/core';
import { ValidatorFn, AbstractControl } from '@angular/forms';
import { FormGroup } from '@angular/forms';

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

  patternValidator(): ValidatorFn {
    return (control: AbstractControl): { [key: string]: any } =&gt; {
      if (!control.value) {
        return null;
      }
      const regex = new RegExp('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9]).{8,}$');
      const valid = regex.test(control.value);
      return valid ? null : { invalidPassword: true };
    };
  }

  MatchPassword(password: string, confirmPassword: string) {
    return (formGroup: FormGroup) =&gt; {
      const passwordControl = formGroup.controls[password];
      const confirmPasswordControl = formGroup.controls[confirmPassword];

      if (!passwordControl || !confirmPasswordControl) {
        return null;
      }

      if (confirmPasswordControl.errors &amp;&amp; !confirmPasswordControl.errors.passwordMismatch) {
        return null;
      }

      if (passwordControl.value !== confirmPasswordControl.value) {
        confirmPasswordControl.setErrors({ passwordMismatch: true });
      } else {
        confirmPasswordControl.setErrors(null);
      }
    }
  }

  userNameValidator(userControl: AbstractControl) {
    return new Promise(resolve =&gt; {
      setTimeout(() =&gt; {
        if (this.validateUserName(userControl.value)) {
          resolve({ userNameNotAvailable: true });
        } else {
          resolve(null);
        }
      }, 1000);
    });
  }

  validateUserName(userName: string) {
    const UserList = ['ankit', 'admin', 'user', 'superuser'];
    return (UserList.indexOf(userName) &gt; -1);
  }
}</code></pre><p>O método <code>patternValidator</code> é usado para validar o padrão de senha no seu formulário. O parâmetro para esse método é do tipo <code>AbstractControl</code>, que é uma classe base para o<code>FormControl</code>.</p><p>Usaremos uma expressão regular para validar a senha. Ela verificará as seguintes quatro condições na senha:</p><ul><li>A senha deve ter, no mínimo, oito caracteres;</li><li>Deve possuir pelo menos uma letra minúscula;</li><li>Deve conter, no mínimo, uma letra maiúscula;</li><li>Deve ter, ao menos, um número.</li></ul><p>Se a senha falhar na verificação da <em>regex</em>, definiremos a propriedade <code>invalidPassword</code> como sendo verdadeira (<em>true</em>).</p><p>O método <code>MatchPassword</code> é usado para comparar as senhas em dois campos. Esse método receberá dois parâmetros do tipo string, os quais representam os nomes dos campos a serem comparados. Utilizaremos o <code>FormControl</code> para esses dois campos e, em seguida, compararemos os valores contidos neles. Se os valores não corresponderem, definiremos a propriedade <code>passwordMismatch</code> como verdadeira (<em>true</em>).</p><p>O método <code>userNameValidator</code> é utilizado para verificar se o nome de usuário já foi utilizado ou não. Esse método receberá um parâmetro do tipo <code>AbstractControl</code>. </p><p>Verificaremos se o valor deste campo está presente em um <em>array </em>estático, <code>UserList</code>. Se o valor inserido pelo usuário já estiver presente, definiremos a propriedade <code>userNameNotAvailable</code> como verdadeira (<em>true</em>).</p><p>Estamos utilizando a função <code>setTimeout</code> para invocar essa verificação a cada dois segundos. Isso assegurará que o erro seja disparado após dois segundos a partir do momento em que o usuário parar de digitar no campo.</p><p>Por questão de simplicidade deste artigo, estamos fazendo o uso de um <em>array </em>estático para buscar a disponibilidade de nomes de usuário. Idealmente, essa deveria ser uma chamada de serviço ao servidor para procurar pelo valor em um banco de dados.</p><h2 id="crie-o-modelo-de-usu-rio"><strong>Crie o modelo de usuário</strong></h2><p>Crie uma pasta chamada <code>models</code> dentro de <code>src/app</code>. Adicione um novo arquivo dentro do diretório <code>models</code>, chamado <code>user.ts</code>. Insira o seguinte código dentro do arquivo <code>user.ts</code>. &nbsp; </p><pre><code>export class User {
    public name: string;
    public email: string;
    public username: string;
    public password: string;
    public confirmPassword: string;
}</code></pre><h2 id="crie-diretivas-customizadas"><strong><strong>Cr</strong>ie diretivas customizadas</strong></h2><p>Criaremos diretivas customizadas para implementar <em>validators</em> customizados para o formulário orientado a <em>templates</em>.</p><p>Execute o comando exibido abaixo para criar a diretiva <code>passwordPattern</code>. </p><pre><code>ng g d directives\passwordPattern</code></pre><p>Este comando criará uma pasta chamada <code>directives</code>, que possui dois arquivos dentro de si – <code>passwordPattern.directive.ts</code> e <code>passwordPattern.directive.spec.ts</code>. Abra o <code>passwordPattern.directive.ts</code> e insira o seguinte código dentro dele.</p><pre><code>import { Directive } from '@angular/core';
import { NG_VALIDATORS, Validator, AbstractControl } from '@angular/forms';
import { CustomvalidationService } from '../services/customvalidation.service';

@Directive({
  selector: '[appPasswordPattern]',
  providers: [{ provide: NG_VALIDATORS, useExisting: PasswordPatternDirective, multi: true }]
})
export class PasswordPatternDirective implements Validator {

  constructor(private customValidator: CustomvalidationService) { }

  validate(control: AbstractControl): { [key: string]: any } | null {
    return this.customValidator.patternValidator()(control);
  }
}</code></pre><p>Essa diretiva é usada para validar o padrão da senha. Implementaremos a interface <code>Validator</code> na classe <code>PasswordPatternDirective</code>. Sobrescreveremos o método <code>validate</code>, o qual recebe um parâmetro do tipo <code>AbstractControl</code>, que é o controle que desejamos validar. Em seguida, invocaremos o método <code>patternValidator</code> do serviço. </p><p>Execute o comando mostrado abaixo para criar a diretiva <code>matchPassword</code>:</p><pre><code>ng g d directives\matchPassword</code></pre><p>Abra o arquivo <code>matchPassword.directive.ts</code> e insira o seguinte código dentro dele:</p><pre><code>import { Directive, Input } from '@angular/core';
import { NG_VALIDATORS, Validator, ValidationErrors, FormGroup } from '@angular/forms';
import { CustomvalidationService } from '../services/customvalidation.service';

@Directive({
  selector: '[appMatchPassword]',
  providers: [{ provide: NG_VALIDATORS, useExisting: MatchPasswordDirective, multi: true }]
})
export class MatchPasswordDirective implements Validator {
  @Input('appMatchPassword') MatchPassword: string[] = [];

  constructor(private customValidator: CustomvalidationService) { }

  validate(formGroup: FormGroup): ValidationErrors {
    return this.customValidator.MatchPassword(this.MatchPassword[0], this.MatchPassword[1])(formGroup);
  }
}</code></pre><p>Essa diretiva é usada para validar se as senhas inseridas nos dois campos correspondem ou não. Essa diretiva receberá uma entrada do tipo <em>array </em>de <em>strings</em>, o qual contém os campos a serem comparados. Sobrescreveremos o método <code>validate</code> e passaremos o parâmetro do tipo <code>FormGroup</code>. Em seguida, invocaremos o método <code>MatchPassword</code> do serviço. &nbsp;</p><p>Execute o comando abaixo para criar a diretiva <code>validateUserName</code>:</p><pre><code>ng g d directives\validateUserName</code></pre><p>Abra o arquivo <code>validateUserName.directive.ts</code> e introduza o seguinte código nele:</p><pre><code>import { Directive, forwardRef } from '@angular/core';
import { Validator, AbstractControl, NG_ASYNC_VALIDATORS } from '@angular/forms';
import { CustomvalidationService } from '../services/customvalidation.service';
import { Observable } from 'rxjs';

@Directive({
  selector: '[appValidateUserName]',
  providers: [{ provide: NG_ASYNC_VALIDATORS, useExisting: forwardRef(() =&gt; ValidateUserNameDirective), multi: true }]

})
export class ValidateUserNameDirective implements Validator {

  constructor(private customValidator: CustomvalidationService) { }

  validate(control: AbstractControl): Promise&lt;{ [key: string]: any }&gt; | Observable&lt;{ [key: string]: any }&gt; {
    return this.customValidator.userNameValidator(control);
  }
}</code></pre><p>Essa diretiva é usada para validar a disponibilidade do nome de usuário. Sobrescreveremos o método <code>validate</code> e passaremos um parâmetro do tipo <code>AbstractControl</code>. Em seguida, invocaremos o método <code>userNameValidator</code> do serviço. Esse método retornará uma <em>promise</em>.</p><h2 id="crie-o-componente-do-formul-rio-orientado-a-templates"><strong><strong>Cr</strong>ie o componente do formulário orientado a <em>templates</em></strong></h2><p>Execute o comando apresentado abaixo para criar o componente do formulário orientado a <em>templates</em>:</p><pre><code>ng g c template-driven-form</code></pre><p>Abra o arquivo <code>template-driven-form.component.ts</code> e insira o seguinte código nele:</p><pre><code>import { Component } from '@angular/core';
import { User } from '../models/user';

@Component({
  selector: 'app-template-driven-form',
  templateUrl: './template-driven-form.component.html',
  styleUrls: ['./template-driven-form.component.scss']
})
export class TemplateDrivenFormComponent {

  userModal = new User();

  constructor() { }

  onSubmit() {
    alert('Form Submitted succesfully!!!\n Check the values in browser console.');
    console.table(this.userModal);
  }
}</code></pre><p>Criamos um objeto <code>userModal</code> do tipo <code>User</code>. Vincularemos os campos do formulário com a propriedade desse objeto. O método <code>onSubmit</code> mostrará a mensagem de sucesso na tela e exibirá os conteúdos do formulário no console.</p><p>Abra o arquivo <code>template-driven-form.component.html</code> e introduza o seguinte código nele:</p><pre><code>&lt;div class="container"&gt;
    &lt;div class="row"&gt;
        &lt;div class="col-md-8 mx-auto"&gt;
            &lt;div class="card"&gt;
                &lt;div class="card-header"&gt;
                    &lt;h3&gt;Angular Template-driven Form&lt;/h3&gt;
                &lt;/div&gt;
                &lt;div class="card-body"&gt;
                    &lt;form class="form" #registerForm="ngForm" [appMatchPassword]="['password', 'confirmPassword']"
                        (ngSubmit)="registerForm.form.valid &amp;&amp; onSubmit()" novalidate&gt;
                        &lt;div class=" form-group"&gt;
                            &lt;label&gt;Name&lt;/label&gt;
                            &lt;input type="text" class="form-control" [(ngModel)]="userModal.name" name="name"
                                #name="ngModel" required&gt;
                            &lt;span class="text-danger"
                                *ngIf="(name.touched || registerForm.submitted) &amp;&amp; name.errors?.required"&gt;
                                Name is required
                            &lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class="form-group"&gt;
                            &lt;label&gt;Email&lt;/label&gt;
                            &lt;input type="text" class="form-control" [(ngModel)]="userModal.email" name="email"
                                #email="ngModel" required email&gt;
                            &lt;span class="text-danger"
                                *ngIf="(email.touched || registerForm.submitted) &amp;&amp; email.errors?.required"&gt;
                                Email is required
                            &lt;/span&gt;
                            &lt;span class="text-danger" *ngIf="email.touched &amp;&amp; email.errors?.email"&gt;
                                Enter a valid email address
                            &lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class="form-group"&gt;
                            &lt;label&gt;User Name&lt;/label&gt;
                            &lt;input type="text" class="form-control" [(ngModel)]="userModal.username" name="username"
                                #username="ngModel" appValidateUserName required&gt;
                            &lt;span class="text-danger"
                                *ngIf="(username.touched || registerForm.submitted) &amp;&amp; username.errors?.required"&gt;
                                User Name is required
                            &lt;/span&gt;
                            &lt;span class="text-danger" *ngIf="username.touched &amp;&amp; username.errors?.userNameNotAvailable"&gt;
                                User Name not available
                            &lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class="form-group"&gt;
                            &lt;label&gt;Password&lt;/label&gt;
                            &lt;input type="password" class="form-control" [(ngModel)]="userModal.password" name="password"
                                #password="ngModel" appPasswordPattern required&gt;
                            &lt;span class="text-danger"
                                *ngIf="(password.touched || registerForm.submitted) &amp;&amp; password.errors?.required"&gt;
                                Password is required
                            &lt;/span&gt;
                            &lt;span class="text-danger" *ngIf="password.touched &amp;&amp; password.errors?.invalidPassword"&gt;
                                Password should have minimum 8 characters, at least 1 uppercase letter, 1 lowercase
                                letter and 1 number
                            &lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class="form-group"&gt;
                            &lt;label&gt;Confirm Password&lt;/label&gt;
                            &lt;input type="password" class="form-control" [(ngModel)]="userModal.confirmPassword"
                                name="confirmPassword" #confirmPassword="ngModel" required&gt;
                            &lt;span class="text-danger"
                                *ngIf="(confirmPassword.touched || registerForm.submitted) &amp;&amp; confirmPassword.errors?.required"&gt;
                                Confirm Password is required
                            &lt;/span&gt;
                            &lt;span class="text-danger"
                                *ngIf="confirmPassword.touched &amp;&amp; confirmPassword.errors?.passwordMismatch"&gt;
                                Passwords doesnot match
                            &lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class="form-group"&gt;
                            &lt;button type="submit" class="btn btn-success"&gt;Register&lt;/button&gt;
                        &lt;/div&gt;
                    &lt;/form&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;</code></pre><p>Criaremos um formulário orientado a <em>templates</em> e usaremos o card do Bootstrap para estilização. O <code>card-header</code> conterá um título, enquanto o <code>card-body</code> terá os campos do formulário.</p><p>Usaremos a diretiva <code>appMatchPassword</code> em nosso formulário e passaremos para validação os campos de senha e <code>confirmPassword</code>. A propriedade <code>ngModel</code> é usada para vincular o controle do formulário ao modelo.</p><p>Para validar a disponibilidade do nome de usuário, usaremos a diretiva <code>appValidateUserName</code> no campo <code>username</code>. Do mesmo modo, utilizaremos a diretiva <code>appPasswordPattern</code> no campo de senha para validar o padrão da senha.</p><p>Verificaremos os erros nos controles do formulário e, então, exibiremos na tela a mensagem de erro de validação apropriada.</p><h2 id="crie-um-componente-nav-bar"><strong><strong>Cr</strong>ie um componente nav-bar</strong></h2><p>Execute o comando abaixo para criar um componente <code>nav-bar</code>:</p><pre><code>ng g c nav-bar</code></pre><p>Abra o arquivo <code>nav-bar.component.html</code> e insira nele o seguinte código:</p><pre><code>&lt;nav class="navbar navbar-expand-sm navbar-dark bg-dark fixed-top"&gt;
    &lt;a class="navbar-brand" [routerLink]='["/"]'&gt;Form Validation Demo&lt;/a&gt;
    &lt;div class="collapse navbar-collapse"&gt;
        &lt;ul class="navbar-nav mr-auto"&gt;
            &lt;li class="nav-item"&gt;
                &lt;a class="nav-link" [routerLink]='["/template-form"]'&gt;Template Form&lt;/a&gt;
            &lt;/li&gt;
        &lt;/ul&gt;
    &lt;/div&gt;
&lt;/nav&gt;</code></pre><p>Aqui, estamos adicionando o link de navegação para o componente de formulário orientado a <em>templates</em>.</p><h2 id="atualize-o-componente-app"><strong>Atualize o componen<strong>t</strong>e <em>app</em></strong></h2><p>Abra o arquivo <code>app.component.html</code> e introduza nele o código a seguir:</p><pre><code>&lt;app-nav-bar&gt;&lt;/app-nav-bar&gt;
&lt;div class="container"&gt;
  &lt;router-outlet&gt;&lt;/router-outlet&gt;
&lt;/div&gt;</code></pre><h2 id="atualize-o-m-dulo-de-app"><strong>Atualize o módulo de <em>app</em></strong></h2><p>Importaremos o módulo de formulários e, também, configuraremos o roteamento para nossa aplicação no módulo do <code>app</code>. Adicione o seguinte código no arquivo <code>app.module.ts</code>. Você pode consultar o <a href="https://github.com/AnkitSharma-007/angular-forms-validation/blob/master/src/app/app.module.ts">GitHub</a> para obter o código fonte completo deste arquivo:</p><pre><code>import { RouterModule } from '@angular/router';
import { FormsModule } from  '@angular/forms';

@NgModule({
  ...    
  imports: [
    ...
    FormsModule,
    RouterModule.forRoot([
      { path: '', component: TemplateDrivenFormComponent },
      { path: 'template-form', component: TemplateDrivenFormComponent }
    ]),
  ],
})</code></pre><h2 id="execu-o-de-demonstra-o"><strong><strong>Execu</strong>ção de<strong> demo</strong>nstração</strong></h2><p>Use o comando a seguir para iniciar o servidor da web:</p><pre><code>ng serve -o</code></pre><p>Este comando iniciará a aplicação em seu navegador padrão no <code>http://localhost:4200/</code>. Você pode realizar todas as validações de formulário que discutimos aqui.</p><h2 id="resumo">Resumo</h2><p>Criamos um formulário de registro de usuário de exemplo usando a abordagem de formulário orientado a <em>templates</em> no Angular. Implementamos no formulário as validações nativas, assim como as validações customizadas. A biblioteca do Bootstrap foi usada para estilização do formulário.</p><p>Acesse o código-fonte pelo <a href="https://github.com/AnkitSharma-007/angular-forms-validation">GitHub</a> e explore o repositório para ter um melhor entendimento.</p><h2 id="veja-tamb-m-recursos-em-ingl-s-"><strong>Veja também (recursos em inglês)</strong></h2><ul><li><a href="https://ankitsharmablogs.com/reactive-form-validation-in-angular/">Reactive Form Validation In Angular</a></li><li><a href="https://ankitsharmablogs.com/localization-in-angular-using-i18n-tools/">Localization In Angular Using i18n Tools</a></li><li><a href="https://ankitsharmablogs.com/policy-based-authorization-in-angular-using-jwt/">Policy-Based Authorization In Angular Using JWT</a></li><li><a href="https://ankitsharmablogs.com/asp-net-core-using-highcharts-with-angular-5/">ASP.NET Core – Using Highcharts With Angular 5</a></li><li><a href="https://ankitsharmablogs.com/asp-net-core-crud-using-angular-and-entity-framework-core/">ASP.NET Core – CRUD Using Angular And Entity Framework Core</a></li></ul><p>Você pode encontrar este artigo em inglês, <a href="https://ankitsharmablogs.com/template-driven-form-validation-in-angular/">Template-Driven Form Validation In Angular</a>, e outros artigos semelhantes no <a href="https://ankitsharmablogs.com/">blog do autor</a>.<br></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Os melhores exemplos do Angular ]]>
                </title>
                <description>
                    <![CDATA[ > Tradução realizada em português europeu Angular é um framework de código-livre com base no TypeScript, utilizado para desenvolver aplicações de front-end para a web. É o sucessor do AngularJS e todas as menções ao Angular referem-se à versão 2 ou superior. O Angular tem funcionalidades como generics, static-typing e ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/os-melhores-exemplos-do-angular/</link>
                <guid isPermaLink="false">644a78660fb65d064e628271</guid>
                
                    <category>
                        <![CDATA[ Angular ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Afonso Branco ]]>
                </dc:creator>
                <pubDate>Tue, 08 Aug 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/07/angular-examples.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/the-best-angular-examples/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">The Best Angular Examples</a>
      </p><blockquote>Tradução realizada em português europeu</blockquote><p>Angular é um framework de código-livre com base no TypeScript, utilizado para desenvolver aplicações de <em>front-end</em> para a web. É o sucessor do AngularJS e todas as menções ao Angular referem-se à versão 2 ou superior. O Angular tem funcionalidades como <em>generics</em>, <em>static-typing</em> e algumas outras funcionalidades do ES6.</p><h2 id="hist-rico-de-vers-es"><strong>Histórico de versões</strong></h2><p>A Google lançou a versão inicial do AngularJS a 20 de outubro de 2010. A versão estável do AngularJS foi lançada a 18 de dezembro de 2017, com a versão 1.6.8. A última atualização significativa do AngularJS, a versão 1.7, ocorreu a 1 de julho de 2018, e está, atualmente, num período de 3 anos de Suporte a Longo Prazo. O Angular 2.0 foi anunciado pela primeira vez a 22 de setembro de 2014, na conferência ng-Europe. Uma das novas funcionalidades do Angular 2.0 é o carregamento dinâmico. A maior parte das principais funcionalidades foram movidas para módulos.</p><p>Após algumas modificações, o Angular 4.0 foi lançado em dezembro de 2016. O Angular 4 tem compatibilidade com a versão mais antiga do Angular 2.0. Algumas das novas funcionalidades são a biblioteca HttpClient e os novos eventos de ciclo de vida do <em>router</em>. O Angular 5 foi lançado a 1 de novembro de 2017, tendo uma funcionalidade muito importante que é o suporte para aplicações web progressivas. O Angular 6 foi lançado em maio de 2018, enquanto o Angular 7 foi lançado em outubro de 2018. A versão estável mais recente é a <a href="https://angular.io/guide/releases">7.0.0</a>.</p><blockquote>Nota da tradução: o texto que estás a ler é de 2018. A versão mais recente do Angular, no momento desta tradução, é a versão 16.1.2, de 21 de junho de 2023, compatível com as versões 16.14.0 a 18.10.0 do NodeJS, 4.9.3 a 5.2.0 do TypeScript e 6.5.3 a 7.4.0 do RxJS.</blockquote><h2 id="instala-o"><strong>Instalação</strong></h2><p>A forma mais fácil de instalar o Angular é através da <a href="https://cli.angular.io/">Angular CLI</a>. Esta ferramenta permite a criação de projetos e a geração de componentes, serviços, módulos e assim adiante. Como padrão, a equipa do Angular considera que esta seja a melhor prática.</p><h3 id="angular-2-x-e-vers-es-mais-recentes"><strong>Angular 2.x e versões mais recentes</strong></h3><h4 id="instalar-a-angular-cli"><strong>Instalar a Angular CLI</strong></h4><pre><code class="language-shell">npm install -g @angular/cli</code></pre><h4 id="criar-um-espa-o-de-trabalho-e-a-aplica-o-inicial"><strong>Criar um espaço de trabalho e a aplicação inicial</strong></h4><p>Vais desenvolver aplicações no contexto de um espaço de trabalho do Angular. Um espaço de trabalho contém os ficheiros para um ou mais projetos. Um projeto é o conjunto de ficheiros que compõe uma aplicação, uma biblioteca, ou testes <em>end-to-end</em> (e2e).</p><pre><code class="language-shell">ng new my-app</code></pre><h4 id="servir-a-aplica-o"><strong>Servir a aplicação</strong></h4><p>O Angular inclui um servidor para que consigas criar e servir facilmente a tua aplicação localmente.</p><ol><li>Navega até à pasta do espaço de trabalho (<code>my-app</code>)</li></ol><p>Inicia o servidor ao utilizar o comando CLI <code>ng serve</code> com a opção <code>--open</code></p><pre><code class="language-shell">cd my-app
ng serve --open</code></pre><p>Boa, criaste a tua primeira aplicação em Angular!!!</p><p>O Angular contém muitos <em>esquemas</em> para criar aplicações. Os componentes são um desses esquemas. Eles englobam uma única unidade de lógica relacionada com uma única parte da aplicação. Os componentes fazem geralmente parceria com outros esquemas para operar de maneira mais eficiente.</p><p>Os componentes simplificam a aplicação. Canalizar a lógica para uma única secção da interface visível é o seu principal objetivo. Para criar aplicações passo a passo, precisas de criar componente a componente. No final de contas, os componentes funcionam como blocos de construção do Angular.</p><h3 id="classe-de-componente-e-metadados"><strong>Classe de componente e metadados</strong></h3><p>O comando da CLI <code>ng generate component [nome-do-componente]</code> produz o seguinte:</p><pre><code class="language-typescript">import { Component, OnInit } from '@angular/core';

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

  ngOnInit() { }
}</code></pre><p>Esta é a estrutura básica da qual todos os grandes componentes se originam. O <em>decorator</em> <code>@Component</code> é a parte mais importante. Sem ele, o exemplo acima torna-se uma classe genérica. O Angular depende dos <em>decorators</em> para distinguir o tipo esquemático da classe.</p><p><code>@Component</code> recebe metadados como um único objeto. Os <em>decorators</em> são apenas funções JavaScript em segundo plano. Eles recebem argumentos assim como o objeto de metadados. O objeto de metadados configura as dependências básicas do componente. Cada campo tem o seu papel.</p><ul><li><code>selector:</code> indica ao Angular para associar o componente a um determinado elemento no <em>template </em>HTML da aplicação.</li><li><code>templateUrl:</code> aceita a localização do ficheiro do <em>template </em>HTML do componente (é também aqui que a informação é exibida).</li><li><code>styleUrls:</code> aceita um array de localizações de ficheiros das folhas de estilos (strings). Estas folhas de estilos focam o <em>template </em>atribuído ao componente.</li></ul><p>Pensa em metadados como uma grande bolha de configuração. O <em>decorator </em>recebe-os de maneira a que possa gerar a informação específica ao componente. O <em>decorator</em> <em><em>decora</em></em> a classe subjacente com informação necessária para o comportamento da sua classe, ou seja, uma classe de <em><em>component</em>e</em>.</p><p>A assinatura da classe é exportada por padrão, de maneira a que o componente possa ser importado. <code>ngOnInit</code> é também implementado. <code>implements</code> indica à classe para definir certos métodos de acordo com a definição da interface. <code>ngOnInit</code> é um <em>hook</em> de ciclo de vida.</p><h3 id="informa-es-de-componente"><strong>Informações de componente</strong></h3><p>A informação comanda tudo. Os componentes não são exceção. Os componentes englobam toda a informação. Para receber dados externamente, um componente deve declarar isso explicitamente. Este modo de privacidade impede que a informação entre em conflito ao longo da árvore de componentes.</p><p>A informação determina o que é exibido da classe de componente para o teu <em>template</em>. Qualquer atualização à informação da classe atualizará (ou, pelo menos, deverá atualizar) a visualização do <em>template</em>.</p><p>Os componentes, geralmente, vão inicializar um conjunto de membros (ou variáveis) que armazenam informação. São utilizados ao longo da lógica da classe de componente por conveniência. Essa informação alimenta a lógica resultante no <em>template </em>e o seu comportamento. Observa o seguinte exemplo:</p><pre><code class="language-typescript">// ./components/example/example.component.ts

import { Component, OnInit } from '@angular/core';
import { Post, DATA } from '../../data/posts.data';

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html'
})
export class ExampleComponent implements OnInit {
  username: string;
  totalPosts: number;
  allPosts: Post[];

  deletePost(index: number): void {
    this.allPosts.splice(index, 1);
    this.totalPosts = this.allPosts.length;
  }

  ngOnInit(): void {
    this.username = DATA.author;
    this.totalPosts = DATA.thePosts.length;
    this.allPosts = DATA.thePosts;
  }
}</code></pre><pre><code class="language-html">&lt;!-- ./components/example/example.component.html --&gt;

&lt;h1&gt;{{ username }}&lt;/h1&gt;
&lt;span&gt;Alterar o nome: &lt;/span&gt;&lt;input [(ngModel)]="username"&gt;
&lt;h3&gt;Publicações: {{ totalPosts }}&lt;/h3&gt;
&lt;ul&gt;
&lt;hr/&gt;
&lt;div *ngFor="let post of allPosts; let i=index"&gt;
  &lt;button (click)="deletePost(i)"&gt;EXCLUIR&lt;/button&gt;
  &lt;h6&gt;{{ post.title }}&lt;/h6&gt;
  &lt;p&gt;{{ post.body }}&lt;/p&gt;
  &lt;hr/&gt;
&lt;/div&gt;
&lt;/ul&gt;</code></pre><p>Repara nas formas como o componente interage com a informação. Primeiro, vai buscar a <code>../../data/posts.data</code> antes de começar a encaminhar para o <em>template </em>para exibir.</p><p>A informação aparece ao longo do <em>template</em>. Dentro de chavetas, o valor de uma variável é mapeado da classe de componente para as chavetas. O <code>*ngFor</code> itera pela classe de array <code>allPosts</code>. Clicar no botão remove um elemento específico de <code>allPosts</code> pelo seu índice. Podes até alterar o <code>username</code> mais acima ao escrever na caixa de <em>input</em>.</p><p>As interações acima alteram a informação da classe de componente que, por sua vez, altera o <em>template </em>HTML do componente. Os componentes fornecem a lógica principal, que facilita o fluxo da informação. O <em>template </em>HTML torna essa informação legível para o utilizador.</p><h2 id="liga-o-binding-dos-dados"><strong>Ligação (binding) dos dados</strong></h2><p>A informação define geralmente o aspeto de uma aplicação. Interpretar essa informação para a interface de utilizador envolve a lógica de classe (<code>*.component.ts</code>) e uma vista de <em>template </em>(<code>*.component.html</code>) . O Angular conecta-os através da ligação (do inglês, <em>binding</em>) dos dados. Pensa na ligação dos dados como uma ferramenta para interação de componentes.</p><h3 id="componente-e-template"><strong>Componente e <em>template</em></strong></h3><p>O componente armazena maior parte da sua lógica e informação dentro da sua classe decorada com <code>@Component</code>. Esse <em>decorator </em>define a classe como um componente com <em>template </em>HTML. O template do componente representa a classe dentro da aplicação. Aqui, o foco deve ser entre a classe do componente e o <em>template </em>HTML.</p><p>É aqui que a ligação de dados ocorre. As propriedades de elementos e eventos recebem valores. Esses valores, definidos pela classe de componente, servem um de dois propósitos. Um é produzir informação que o <em>template </em>receberá. O outro é lidar com os eventos emitidos pelo elemento de <em>template</em>.</p><h3 id="propriedades-de-elemento"><strong>Propriedades de elemento</strong></h3><p>Para reconhecer propriedades de elemento vinculadas aos dados, o Angular utiliza uma sintaxe especial de chavetas.</p><pre><code class="language-typescript">// my.component.ts
@Component({
  templateUrl: './my.component.html'
})

export class MyComponent {
  value:type = /* algum valor de tipo */;
}</code></pre><pre><code class="language-html">&lt;!-- my.component.html --&gt;
&lt;any-element [property]="value"&gt;innerHTML&lt;/any-element&gt;</code></pre><p>Tem paciência comigo aqui.</p><p><code>[property]</code> espelha a propriedade no nó do objeto do elemento no Domain Object Model (DOM). Não confundas propriedades de objeto com um atributo de elemento do DOM. As propriedades e os atributos partilham por vezes o mesmo nome e fazem a mesma coisa. No entanto, existe uma clara distinção.</p><p>Lembra-te de que <code>attr</code> (atributos) é uma única propriedade do objeto do DOM subjacente. A declaração é feita na instanciação do DOM, com valores de atributo correspondentes à definição do elemento. O elemento mantém o mesmo valor após isso. Cada propriedade tem o seu próprio campo chave-valor num nó de objeto do DOM. Essas propriedades são mutáveis após a instanciação.</p><p>Compreende a diferença entre atributos e propriedades. Isso levará a uma melhor compreensão de como o Angular vincula a informação às propriedades (vinculação de propriedade). O Angular raramente vinculará a informação ao atributo de um elemento. As excepções a isso são muito raras. Uma última vez: o Angular vincula a informação de componente às propriedades, não aos atributos!</p><p>Voltando ao exemplo, o <code>[ … ]</code> na atribuição da propriedade do elemento tem um significado especial. Os parênteses retos mostram que <code>property</code> está vinculado ao <code>"value"</code> à direita da atribuição.</p><p><code>value</code> também tem significado especial no contexto dos parênteses retos. O próprio <code>value</code> é uma string literal. O Angular faz a leitura e compara o seu valor ao dos membros da classe. O Angular substituirá o valor do atributo de membro correspondente. Claro que isto refere-se à mesma classe de componente que hospeda o <em>template </em>HTML.</p><p>O fluxo unidirecional de informação do componente para o <em>template </em>está completo. O membro correspondente à atribuição correta da propriedade entre parênteses retos fornece o <code>value</code>. Nota que alterações ao valor do membro na classe do componente filtram para baixo para o <em>template</em>. Essa é a deteção de alteração do Angular em funcionamento. Alterações dentro do âmbito do template não tem efeito no membro da classe do componente.</p><p>Informação principal: a classe de componente fornece a informação enquanto que o <em>template </em>a exibe.</p><p>Não mencionei que os valores da informação também podem aparecer num <code>innerHTML</code> de um componente. Este último exemplo implementa chavetas duplas. O Angular reconhece essas chavetas e interpola a classe de dados de componente correspondente para o <code>innerHTML</code> da <code>div</code>.</p><pre><code class="language-html">&lt;div&gt;O valor do membro 'value', da classe de componente, é {{value}}.&lt;/div&gt;</code></pre><h3 id="lidar-com-eventos"><strong>Lidar com eventos</strong></h3><p>Se o componente fornece dados, então o <em>template </em>fornece eventos.</p><pre><code class="language-typescript">// my.component.ts
@Component({
  templateUrl: './my.component.html'
})

export class MyComponent {
  handler(event):void {
      // a função faz algo
  }
}</code></pre><pre><code class="language-html">// my.component.html
&lt;any-element (event)=“handler($event)”&gt;innerHTML&lt;/any-element&gt;</code></pre><p>Isto funciona de maneira semelhante à vinculação de propriedades.</p><p>O <code>(event)</code> refere-se a qualquer tipo de evento válido. Por exemplo, um dos tipos de eventos mais comum é o <code>click</code>. Ele emite quando <em><em>clic</em>as</em> com o rato. Independentemente do tipo, o <code>event</code> está vinculado ao <code>"handler"</code> no exemplo. Os gestores de eventos são geralmente funções de membro da classe de componente.</p><p>Os <code>( … )</code> são especiais para o Angular. Os parênteses indicam ao Angular que um evento está vinculado à atribuição correta do <code>handler</code>. O próprio evento origina a partir do elemento hospedeiro.</p><p>Quando o evento emite, ele passa o objeto Event sob a forma de <code>$event</code>. O <code>handler</code> mapeia para a função que tem o mesmo nome do <code>handler</code> da classe de componente. A troca unidirecional do elemento vinculado ao evento para a classe de componente está finalizada.</p><p>Os eventos de emissão do gestor, enquanto possível, não causam impacto no elemento de <em>template</em>. Afinal, a vinculação é unidirecional.</p><h2 id="diretrizes"><strong>Diretrizes</strong></h2><p>Diretrizes são elementos de componente e atributos criados e reconhecidos pelo Angular. O Angular associa o elemento ou atributo com a sua definição de classe correspondente. <code>@Directive</code> ou <code>@Component</code> decora essas classes. Ambos são indicativos para o Angular que a classe funciona como uma diretriz.</p><p>Algumas diretrizes modificam o estilo do elemento hospedeiro. Outras diretrizes exibem vistas ou inserem em vistas já existentes como vistas incorporadas. Por outras palavras, elas alteram o layout HTML.</p><p>De qualquer forma, as diretrizes sinalizam o compilador do Angular. Elas marcam componentes para modificação, dependendo da lógica da classe da diretriz.</p><h3 id="diretriz-estrutural"><strong>Diretriz estrutural</strong></h3><p>Aqui estão três exemplos de diretrizes estruturais. Cada uma tem uma contrapartida lógica (<code>if</code>, <code>for</code> e <code>switch</code>).</p><ul><li>*ngIf</li><li>*ngFor</li><li>*ngSwitchCase e *ngSwitchDefault</li></ul><p><strong>Nota i<strong><strong><strong>mportante:</strong></strong></strong></strong> todas as três estão disponíveis através da importação do <code>CommonModule</code>, que está disponível a partir de <code>@angular/common</code> para importação dentro do módulo raiz da aplicação.</p><h5 id="-ngif"><strong>*ngIf</strong></h5><p><code>*ngIf</code> testa um determinado valor para ver se é <em>verdadeiro</em> ou <em><em>fals</em>o</em> com base na avaliação booleana geral em JavaScript. Em caso de ser verdadeiro, o elemento e o seu innerHTML vão ser exibidos. Caso contrário, nunca vão renderizar para o Domain Object Model (DOM).</p><pre><code class="language-html">&lt;!-- renders "&lt;h1&gt;Olá!&lt;/h1&gt;" --&gt;
&lt;div *ngIf="true"&gt;
  &lt;h1&gt;Olá!&lt;/h1&gt;
&lt;/div&gt;

&lt;!-- não renderiza --&gt;
&lt;div *ngIf="false"&gt;
  &lt;h1&gt;Alô!&lt;/h1&gt;
&lt;/div&gt;</code></pre><p>Esse é um exemplo fictício. Qualquer valor de membro da classe de componente do template pode ser substituído por <code>true</code> ou <code>false</code>.</p><p><strong>Nota:</strong> também podes fazer o seguinte com *ngIf para obter acesso ao valor observável:</p><pre><code class="language-html">&lt;div *ngIf="observable$ | async as oNomeQueQuiseres"&gt;
  {{ oNomeQueQuiseres }}
&lt;/div&gt;</code></pre><h5 id="-ngfor"><strong>*ngFor</strong></h5><p><code>*ngFor</code> itera com base numa expressão, <em><em>micros</em>sin<em>tá</em>tica, </em>atribuída à direita. A microssintaxe vai para além do âmbito deste artigo. Fica apenas a saber que a microssintaxe é uma forma abreviada de uma expressão lógica. Ocorre como uma única <em>string</em> capaz de referenciar valores de membro de classe. Podes iterar através de valores iteráveis, o que os torna úteis para <code>*ngFor</code>.</p><pre><code class="language-html">&lt;ul&gt;
  &lt;li *ngFor=“let potato of ['Russet', 'Doce', 'Rosalinda']; let i=index”&gt;
      Potato {{ i + 1 }}: {{ potato }}
  &lt;/li&gt;
  &lt;!-- Resultados
  &lt;li&gt;
      Batata 1: Russet
  &lt;/li&gt;
  &lt;li&gt;
      Batata 2: Doce
  &lt;/li&gt;
  &lt;li&gt;
      Batata 3: Rosalinda
  &lt;/li&gt;
  --&gt;
&lt;/ul&gt;</code></pre><p><code>['Russet', 'Doce', 'Rosalinda']</code> é um valor iterável. Os arrays são uns dos valores iteráveis mais comuns. O <code>*ngFor</code> cria um <code>&lt;li&gt;&lt;/li&gt;</code> por cada elemento do array. É atribuído a cada elemento do array a variável <code>potato</code> (em português, batata). Isto é feito ao utilizar a microssintaxe. O <code>*ngFor</code> define o conteúdo estrutural do elemento <code>ul</code>. Isso é característico de uma diretriz estrutural.</p><p><strong>Nota:</strong> também podes fazer o seguinte com a diretriz <code>*ngFor</code> para obter acesso ao valor observável (atalho):</p><pre><code class="language-html">&lt;div *ngFor="let oNomeQueQuiseres of [(observable$ | async)]"&gt;
  {{  oNomeQueQuiseres }}
&lt;/div&gt;</code></pre><h5 id="-ngswitchcase-e-ngswitchdefault"><strong>*ngSwitchCase e *ngSwitchDefault</strong></h5><p>Estas duas diretrizes estruturais trabalham em conjunto para fornecer a funcionalidade <code>switch</code> ao <em>template </em>HTML.</p><pre><code class="language-html">&lt;div [ngSwitch]="potato"&gt;
  &lt;h1 *ngSwitchCase="'Russet'"&gt;{{ potato }} é uma batata Russet.&lt;/h1&gt;
  &lt;h1 *ngSwitchCase="'Sweet'"&gt;{{ potato }} é uma batata doce.&lt;/h1&gt;
  &lt;h1 *ngSwitchCase="'Laura'"&gt;{{ potato }} é uma batata Rosalinda.&lt;/h1&gt;
  &lt;h1 *ngSwitchDefault&gt;{{ potato }} é um tipo diferente de batata.&lt;/h1&gt;
&lt;/div&gt;</code></pre><p>Apenas uma das expressões <code>*ngSwitch…</code> é renderizada. Repara no atributo <code>[ngSwitch]</code> dentro do elemento <code>div</code> a envolver o switch. Ele passa o valor de <code>potato</code> ao longo da cadeia <code>*ngSwitch...</code>. Essa cadeia de diretrizes estruturais determina que elemento <code>h1</code> renderiza.</p><p>Como tal, <code>[ngSwitch]</code> não é uma diretriz estrutural ao contrário das instruções <code>*ngSwitch…</code>. Ele passa o valor enquanto que o bloco determina o layout final do HTML.</p><p>Lembra-te de que a estilização e passagem de valores não são da responsabilidade das diretrizes estruturais. Isto é responsabilidade das diretrizes de atributos. As diretrizes estruturais determinam apenas o layout.</p><p>As transformações à informação resultante garantem que a informação esteja num formato adequado quando chega a hora de carregar para o ecrã do utilizador. Normalmente, as transformações de informação ocorrem em segundo plano. Com <em>pipes</em>, a transformação de informação pode ocorrer no <em>template </em>HTML. Os <em>pipes</em> transformam a informação de <em>template </em>diretamente.</p><p>Os <em>pipes</em> têm bom aspeto e são convenientes. Eles ajudam a manter a classe de componente com poucas transformações básicas. Tecnicamente, os <em>pipes</em> expressam a lógica da transformação de informação.</p><h3 id="casos-de-utiliza-o"><strong>Casos de utilização</strong></h3><p>O Angular vem carregado com um conjunto básico de <em>pipes</em>. Trabalhar com um par deles desenvolverá a intuição para lidar com os restantes. A lista a seguir fornece três exemplos:</p><ul><li>AsyncPipe</li><li>DatePipe</li><li>TitleCasePipe</li></ul><h5 id="asyncpipe"><strong>AsyncPipe</strong></h5><p>Essas secções requerem uma compreensão básica de <em>Promises</em> ou <em>Observables</em> para apreciar totalmente. O <em>AsyncPipe</em> opera num dos dois. O <em>AsyncPipe</em> extrai informação das <em>Promises</em>/<em>Observables</em> como resultado para o que vier a seguir.</p><p>No caso dos <em>Observables</em>, o <em>AsyncPipe</em> subscreve automaticamente para a fonte de informação. Independentemente de onde vier a informação, o <em>AsyncPipe</em> subscreve para a fonte observável. O <code>async</code> é o nome sintático do <em>AsyncPipe,</em> tal como apresentado abaixo.</p><pre><code class="language-html">&lt;ul *ngFor=“let potato of (potatoSack$ | async); let i=index”&gt;
  &lt;li&gt;Batata {{i + 1}}: {{potato}}&lt;/li&gt;
&lt;/ul&gt;</code></pre><p>No exemplo, o <code>potatoSack$</code> é um <em>Observable</em> a aguardar um carregamento de batatas. Assim que as batatas chegarem, quer de maneira síncrona, quer assíncrona, o <em>AsyncPipe</em> recebe-as como um array <em><em>iterá</em>vel</em>. O elemento de lista é, então, preenchido por batatas.</p><h5 id="datepipe"><strong>DatePipe</strong></h5><p>Formatar strings de data requer um pouco de manipulação com o objeto de JavaScript <code>Date</code>. O <em>DatePipe</em> fornece uma forma potente de formatar datas assumindo que o input fornecido está num formato válido de data.</p><h5 id="titlecasepipe"><strong>TitleCasePipe</strong></h5><p>Transforma texto para estilo de título. Coloca em maiúscula a primeira letra de cada palavra e transforma as letras restantes da palavra em minúsculas. As palavras são delimitadas por qualquer caracter de espaço em branco, tal como um espaço, um tab ou caracter de avanço de linha.</p><pre><code class="language-typescript">// example.component.ts

@Component({
  templateUrl: './example.component.html'
})
export class ExampleComponent {
  timestamp:string = ‘2018-05-24T19:38:11.103Z’;
}</code></pre><pre><code class="language-html">&lt;!-- example.component.html --&gt;

&lt;div&gt;Hora atual: {{timestamp | date:‘short’}}&lt;/div&gt;</code></pre><p>O formato do <code>timestamp</code> acima é <a href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a><sup><a href="https://en.wikipedia.org/wiki/ISO_8601">1</a></sup> — não é o mais fácil de ler. O <em>DatePipe</em> (<code>date</code>) transforma o formato de data ISO no formato mais convencional <code>mm/dd/yy, hh:mm AM|PM</code>. Existem muitas outras opções de formatação. Todas estas opções estão na <a href="https://angular.io/api/common/DatePipe">documentação oficial</a>.</p><h4 id="criar-pipes"><strong>Criar <em>pipes</em></strong></h4><p>Embora o Angular tenha apenas um determinado número de <em>pipes</em>, o <em>decorator </em><code>@Pipe</code> permite aos programadores criarem os seus próprios. O processo começa com <code>ng generate pipe [nome-do-pipe]</code>, substituindo <code>[nome-do-pipe]</code> por um nome de ficheiro preferível. Este comando produz o seguinte:</p><pre><code class="language-typescript">import { Pipe, PipeTransform } from ‘@angular/core’;

@Pipe({
  name: 'example'
})
export class ExamplePipe implements PipeTransform {
  transform(value: any, args?: any): any {
      return null;
  }
}</code></pre><p>Este template de <em>pipe</em> simplifica a criação de um <em>pipe</em> personalizado. O <em>decorator </em><code>@Pipe</code> indica ao Angular que a classe é um <em>pipe</em>. O valor de <code>name: ‘example’</code>, sendo neste caso <code>example</code>, é o valor que o Angular reconhece quando procura no <em>template </em>HTML por <em>pipes</em> personalizados.</p><p>Avancemos para a lógica da classe. A implementação <code>PipeTransform</code> fornece as instruções para a função <code>transform</code>. Esta função tem significado especial dentro do contexto do <em>decorator</em> <code>@Pipe</code>. Ela recebe dois parâmetros de início.</p><p><code>value: any</code> é o resultado que o <em>pipe</em> recebe. Pensa no <code>&lt;div&gt;{{ umValor | example }}&lt;/div&gt;</code>. O valor de <em>umValor</em> é passado para o parâmetro <code>value: any</code> da função <code>transform</code>. Esta é a mesma função <code>transform</code> definida na classe <em>ExamplePipe</em>.</p><p><code>args?: any</code> é qualquer argumento que o <em>pipe</em> recebe opcionalmente. Pensa em <code>&lt;div&gt;{{ umValor | example:[um-argumento] }}&lt;/div&gt;</code>. <code>[um-argumento]</code> pode ser substituído por qualquer valor. Esse valor é passado para o parâmetro <code>args?: any</code> da função <code>transform</code>. Isto é, a função <code>transform</code> definida na classe do <em>ExamplePipe</em>.</p><p>O que quer que a função retorne, (<code>return null;</code>) passa a ser o resultado da operação de <em>pipe</em>. Observa o próximo exemplo para ver um exemplo completo de <em>ExamplePipe</em>. Dependendo da variável que o <em>pipe</em> recebe, ele passa o valor de entrada ou para maiúscula ou para minúscula &nbsp;no novo resultado. Um argumento inválido ou inexistente fará com que o <em>pipe </em>retorne o mesmo valor de entrada como resultado.</p><pre><code class="language-typescript">// example.pipe.ts

@Pipe({
  name: 'example'
})
export class ExamplePipe implements PipeTransform {
  transform(value:string, args?:string): any {
    switch(args || null) {
      case 'uppercase':
        return value.toUpperCase();
      case 'lowercase':
        return value.toLowerCase();
      default:
        return value;
    }
  }
}</code></pre><pre><code class="language-typescript">// app.component.ts

@Component({
  templateUrl: 'app.component.html'
})
export class AppComponent {
  someValue:string = "HeLlO WoRlD!";
}</code></pre><pre><code class="language-html">&lt;!-- app.component.html --&gt;

&lt;!-- Outputs “HeLlO WoRlD!” --&gt;
&lt;h6&gt;{{ someValue | example }}&lt;/h6&gt;

&lt;!-- Outputs “HELLO WORLD!” --&gt;
&lt;h6&gt;{{ someValue | example:‘uppercase’ }}&lt;/h6&gt;

&lt;!-- Outputs “hello world!” --&gt;
&lt;h6&gt;{{ someValue | example:‘lowercase’ }}&lt;/h6&gt;</code></pre><h2 id="hooks-do-ciclo-de-vida"><strong>Hooks do ciclo de vida</strong></h2><p>Os <em>hooks</em> <em>do ciclo de vida</em> são métodos temporizados. Eles diferem no tempo e na razão pela qual são executados. A alteração de deteção aciona estes métodos. Eles executam dependendo das condições do ciclo atual. O Angular executa constantemente deteção de alterações nos seus dados. Os <em>hooks</em> <em>do ciclo de vida</em> ajudam a gerir os seus efeitos.</p><p>Um aspeto importante destes <em>hooks</em> é a sua ordem de execução. Ela nunca se altera. Eles executam com base numa série previsível de eventos de carregamento produzidos a partir de um ciclo de deteção. Isto torna-os previsíveis. Alguns ativos estão apenas disponíveis depois da execução de um determinado <em>hook</em>. Claro, um <em>hook</em> executa apenas sob determinadas condições definidas na alteração atual do ciclo de deteção.</p><h3 id="por-ordem-de-execu-o-"><strong>Por ordem de execução:</strong></h3><h3 id="ngonchanges"><strong>ngOnChanges</strong></h3><p><code>ngOnChanges</code> é acionado seguindo a modificação do <code>@Input</code> vinculado aos membros da classe. Dados vinculados pelo <em>decorator</em> <code>@Input()</code> vêm de uma fonte externa. Quando uma fonte externa altera os dados numa forma detetável, eles são passados novamente pela propriedade <code>@Input</code>.</p><p>Com essa atualização, <code>ngOnChanges</code> aciona imediatamente. Também é acionado na inicialização dos dados de entrada. O <em>hook</em> recebe um parâmetro opcional do tipo <code>SimpleChanges</code>. Este valor contém informação das propriedades alteradas vinculadas ao valor de entrada.</p><h3 id="ngoninit"><strong>ngOnInit</strong></h3><p><code>ngOnInit</code> é acionado uma vez na inicialização da propriedade (<code>@Input</code>) de um componente vinculado aos dados. O próximo exemplo terá um aspeto semelhante ao anterior. O <em>hook</em> não aciona porque o <em>ChildComponent</em> recebe os dados de entrada. Em vez disso, ele aciona logo após a renderização da informação para o template do <em>ChildComponent</em>.</p><h3 id="ngdocheck"><strong>ngDoCheck</strong></h3><p><code>ngDoCheck</code> é acionado a cada ciclo de deteção de alteração. O Angular executa frequentemente a deteção de alterações. Realizar qualquer ação fará com que faça mais um ciclo. O <code>ngDoCheck</code> é acionado com esses ciclos. Utiliza-o com precaução. Ele pode causar problemas de performance quando implementado incorretamente.</p><p>O <code>ngDoCheck</code> permite aos programadores verificarem os seus dados manualmente. Eles podem acionar uma nova data de aplicação condicionalmente. Juntamente com <code>ChangeDetectorRef</code>, os programadores podem criar as suas próprias verificações para a deteção de mudanças.</p><h3 id="ngaftercontentinit"><strong>ngAfterContentInit</strong></h3><p><code>ngAfterContentInit</code> é acionado depois da inicialização do DOM do conteúdo do componente (quando ele é carregado pela primeira vez). Esperar por <em>queries </em><code>@ContentChild(ren)</code> é o principal caso de utilização do <em>hook</em>.</p><p>As <em>queries </em><code>@ContentChild(ren)</code> produzem referências de elemento para o conteúdo do DOM. Como tal, elas não estão disponíveis até que o conteúdo do DOM carregue. É por isso que <code>ngAfterContentInit</code> e sua contrapartida, <code>ngAfterContentChecked</code>, são utilizados.</p><h3 id="ngaftercontentchecked"><strong>ngAfterContentChecked</strong></h3><p><code>ngAfterContentChecked</code> é acionado depois de cada ciclo de deteção de alteração focado no DOM do conteúdo. Isto permite aos programadores facilitar como o DOM do conteúdo reage a deteção de alterações. O <code>ngAfterContentChecked</code> pode ser acionado frequentemente e causar problemas de performance se for mal implementado.</p><p><code>ngAfterContentChecked</code> também é acionado durante as etapas de inicialização de um componente. Vem logo após o <code>ngAfterContentInit</code>.</p><h3 id="ngafterviewinit"><strong>ngAfterViewInit</strong></h3><p><code>ngAfterViewInit</code> é acionado uma vez depois da vista do DOM terminar a inicialização. A vista carrega sempre logo após o conteúdo. O <code>ngAfterViewInit</code> espera pela resolução das <em>queries </em><code>@ViewChild(ren)</code>. Estes elementos são consultados a partir de dentro da mesma vista do componente.</p><h3 id="ngafterviewchecked"><strong>ngAfterViewChecked</strong></h3><p><code>ngAfterViewChecked</code> é acionado depois de qualquer ciclo de deteção de alterações focado na vista do componente. O <em>hook</em> <code>ngAfterViewChecked</code> permite aos programadores facilitar como a deteção de alterações afeta a vista do DOM.</p><h3 id="ngondestroy"><strong>ngOnDestroy</strong></h3><p><code>ngOnDestroy</code> é acionado quando um componente é removido da vista e do DOM subsequente. Este <em>hook</em> fornece uma oportunidade para limpar qualquer ponta solta antes de remover um componente.</p><h2 id="vistas"><strong>Vistas</strong></h2><p>As vistas são quase como o seu próprio DOM virtual. Cada vista contém uma referência para uma secção correspondente do DOM. Dentro de uma vista estão nós que espelham o que está nesta secção. O Angular atribui um nó de vista por cada elemento DOM. Cada nó tem uma referência para um elemento correspondente.</p><p>Quando o Angular procura por alterações, este verifica as vistas. O Angular evita o DOM em segundo plano. As vistas referenciam o DOM em seu nome. Existem outros mecanismos para garantir que as alterações de vista renderizem no DOM. Por outro lado, alterações ao DOM não afetam as vistas.</p><p>Novamente, as vistas são comuns ao longo de todas as plataformas de desenvolvimento para além do DOM. Mesmo no desenvolvimento para uma plataforma, as vistas ainda são consideradas melhor prática. Elas garantem que o Angular tenha uma interpretação correta do DOM.</p><p>As vistas podem não existir em bibliotecas externas. A manipulação direta do DOM é uma saída de emergência para este tipo de cenário. Certamente, não esperes que a aplicação funcione em várias plataformas.</p><h3 id="tipos-de-vistas"><strong>Tipos de vistas</strong></h3><p>Existem dois tipos principais de vistas: incorporada e de anfitrião.</p><p>Também existem recipientes de vista. Eles armazenam vistas incorporadas e de anfitrião e são geralmente referidos como "vistas" simples.</p><p>Qualquer classe <code>@Component</code> regista um recipiente de vista (vista) com Angular. Novos componentes geram um seletor personalizado focado num determinado elemento do DOM. A vista anexa-se a esse elemento quando ele aparecer. O Angular sabe agora que o componente existe ao olhar para o modelo de vista.</p><h3 id="vistas-de-anfitri-o-e-recipientes"><strong>Vistas de anfitrião e recipientes</strong></h3><p>Vistas de anfitrião <em><em>hos</em>pedam</em> componentes dinâmicos. Recipientes de vista (vistas) são anexados automaticamente a elementos já existentes no <em>template</em>. As vistas podem ser anexadas a qualquer elemento para além do que é único em classes de componente.</p><p>Pensa no método tradicional da geração de componente. Ele começa por criar uma classe, decorá-la com <code>@Component</code>, e preenchê-la com metadados. Esta abordagem ocorre em qualquer elemento de componente predefinido do template.</p><p>Tenta utilizar o comando da interface da linha de comandos do Angular (CLI): <code>ng generate component [name-of-component]</code>. Ele produz o seguinte:</p><pre><code class="language-typescript">import { Component, OnInit } from '@angular/core';

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

  ngOnInit() { }
}</code></pre><p>Isso cria o componente com o seletor <code>app-example</code>. Ele anexa um recipiente de vista a <code>&lt;app-example&gt;&lt;/app-example&gt;</code> no template. Se essa for a raiz da aplicação, a sua vista encapsularia todas as outras vistas. A vista raiz marca o início da aplicação na perspetiva do Angular.</p><p>Criar componentes dinamicamente e registá-los no modelo de vista do Angular requer mais alguns passos. As diretrizes estruturais ajudam a gerir conteúdo dinâmico (<code>*ngIf, *ngFor, e *ngSwitch…</code>). No entanto, as diretrizes não escalam para aplicações maiores. Demasiadas diretrizes estruturais complicam o <em>template</em>.</p><p>É aqui que instanciar componentes a partir de lógicas de classe existentes vem a calhar. Estes componentes precisam de criar uma vista de anfitrião que pode inserir no modelo de vista. As vistas de anfitrião armazenam dados para componentes de maneira a que o Angular reconheça o seu propósito estrutural.</p><h3 id="vistas-incorporadas"><strong>Vistas incorporadas</strong></h3><p>Diretrizes estruturais criam um <code><a href="https://angular.io/guide/structural-directives#the-asterisk--prefix">ng-template</a></code> <a href="https://angular.io/guide/structural-directives#the-asterisk--prefix">à volta de um pedaço de conteúdo do HTML</a>. O elemento anfitrião da diretriz tem um recipiente de vista anexado. Isto faz com que o conteúdo possa renderizar à condição no seu layout pretendido.</p><p>O <code>ng-template</code> armazena nós de vista incorporados a representar cada elemento dentro do seu innerHTML. <code>ng-template</code> não é de todo um elemento do DOM. Ele comenta-se a si próprio. As tags definem a extensão da sua vista incorporada.</p><p>Instanciar uma vista incorporada não requer recursos externos para além da sua própria referência. A <em>query </em><code>@ViewChild</code> pode ir buscar isso.</p><p>Com a referência do <em>template</em>, chamar <code>createEmbeddedView</code> a partir dele dá conta do recado. O innerHTML da referência passa a ser a sua própria instância de vista incorporada.</p><p>No próximo exemplo, <code>&lt;ng-container&gt;&lt;/ng-container&gt;</code> é um recipiente de vista. O <code>ng-container</code> é comentado durante a compilação, tal como o <code>ng-template</code>. Por isso, ele fornece uma saída para inserir a vista incorporada mantendo o DOM leve.</p><p>O <em>template </em>de vista incorporada é inserido na localização de layout do <code>ng-container</code>. Esta vista recentemente inserida não tem encapsulamento de vista adicional para além do recipiente de vista. Lembra-te de como isto é diferente das vistas de anfitrião (as vistas de anfitrião são anexadas ao seu invólucro de elemento <code>ng-component</code>).</p><pre><code class="language-typescript">import { Component, AfterViewInit, ViewChild,
ViewContainerRef, TemplateRef } from '@angular/core';

@Component({
  selector: 'app-example',
  template: `
  &lt;h1&gt;Application Content&lt;/h1&gt;
  &lt;ng-container #container&gt;&lt;/ng-container&gt; &lt;!-- embed view here --&gt;
  &lt;h3&gt;End of Application&lt;/h3&gt;

  &lt;ng-template #template&gt;
    &lt;h1&gt;Template Content&lt;/h1&gt;
    &lt;h3&gt;Dynamically Generated!&lt;/h3&gt;
  &lt;/ng-template&gt;
  `
})
export class ExampleComponent implements AfterViewInit {
  @ViewChild("template", { read: TemplateRef }) tpl: TemplateRef&lt;any&gt;;
  @ViewChild("container", { read: ViewContainerRef }) ctr: ViewContainerRef;

  constructor() { }

  ngAfterViewInit() {
    const view =  this.tpl.createEmbeddedView(null);
    this.ctr.insert(view);
  }
}</code></pre><p>As <em>queries </em><code>@ViewChild</code> para o <em>template fazem referência à variável </em><code>#template</code>. Isto fornece uma referência de <em>template </em>do tipo <code>TemplateRef</code>. <code>TemplateRef</code> armazena a função <code>createEmbeddedView</code>. Esta instancia o <em>template </em>como uma vista incorporada.</p><p>O único argumento de <code>createEmbeddedView</code> é para contexto. Se desejares passar metadados adicionais, podes fazê-lo aqui como um objeto. Os campos devem corresponder aos atributos de <code>ng-template</code> (<code>let-[context-field-key-name]=“value”</code>). Passar <code>null</code> indica que não são necessários mais metadados.</p><p>Uma segunda <em>query </em><code>@ViewChild</code> fornece uma referência a <code>ng-container</code> como um <code>ViewContainerRef</code>. As vistas incorporadas são apenas anexadas a outras vistas, nunca ao DOM. O <code>ViewContainerRef</code> referencia a vista que recebe a vista incorporada.</p><p>Uma vista incorporada também pode ser inserida na vista de componente do <code>&lt;app-example&gt;&lt;/app-example&gt;</code>. Esta abordagem posiciona a vista no final da vista do ExampleComponent. No entanto, neste exemplo, queremos que o conteúdo apareça mesmo no meio, onde está <code>ng-container</code>.</p><p>A função <code>insert</code> do <code>ViewContainerRef</code> <em><em>inser</em>e</em> a vista incorporada no <code>ng-container</code>. O conteúdo da vista aparece no local pretendido, no centro da vista do ExampleComponent.</p><h2 id="redirecionamento"><strong>Redirecionamento</strong></h2><p>O redirecionamento é essencial. Muitas aplicações da web modernas hospedam demasiada informação para uma página. Os utilizadores também não devem ter de percorrer todo o conteúdo de uma página. Uma aplicação precisa de se dividir em secções distintas. Uma boa prática do Angular é carregar e configurar o redirecionamento num módulo separado, de nível superior, que é dedicado ao redirecionamento e importado pela raiz, AppModule.</p><p>Os utilizadores dão prioridade a informações necessárias. O redirecionamento ajuda-os a encontrar a secção da aplicação com tal informação. Qualquer outra informação útil para outros utilizadores pode existir num caminho totalmente diferente. Com redirecionamento, ambos os utilizadores podem encontrar o que precisam rapidamente. Detalhes irrelevantes permanecem escondidos atrás de caminhos irrelevantes.</p><p>O redirecionamento funciona muito bem ao ordenar e restringir acesso a dados da aplicação. Informação sensível nunca deve ser exibida a utilizadores não autorizados. A aplicação pode intervir entre cada caminho. Ela pode examinar a sessão de um utilizador por questões de autenticação. Este exame determina que caminho deve ser renderizado. O redirecionamento dá aos programadores a oportunidade perfeita para validar um utilizador antes de proceder.</p><p>Quanto ao Angular, o redirecionamento ocupa toda a sua própria biblioteca dentro do framework. Todos os frameworks modernos de <em>front-end</em> suportam redirecionamento – o Angular não é exceção. O redirecionamento acontece no lado do <em>client</em> utilizando quer redirecionamento de hash, quer de localização. Ambos os estilos permitem ao <em>client</em> gerir os seus próprios caminhos. Não é necessária assistência adicional por parte do servidor após o pedido inicial.</p><h3 id="redirecionamento-b-sico"><strong>Redirecionamento básico</strong></h3><p>Os utilitários de redirecionamento exportam com o <code>RouterModule</code> disponível em <code>@angular/router</code>. Não faz parte da biblioteca principal, visto que nem todas as aplicações requerem redirecionamento. A forma mais convencional de introduzir redirecionamento é com o seu próprio <a href="https://angular.io/guide/feature-modules">módulo de recursos</a>.</p><p>À medida que a complexidade cresce, ter o seu próprio módulo irá promover a simplicidade do módulo raiz. Mantê-lo estupidamente simples, sem comprometer a funcionalidade, constitui um bom design para os módulos.</p><pre><code class="language-typescript">import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { AComponent } from '../../components/a/a.component';
import { BComponent } from '../../components/b/b.component';

// um array de futuros caminhos!
const routes: Routes = [];

@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule { }</code></pre><p><code>.forRoot(...)</code> é uma função de classe disponível a partir da classe RouterModule. A função aceita um array de objetos <code>Route</code> como <code>Routes</code>. O <code>.forRoot(...)</code> configura caminhos para <em>eager-loading,</em> enquanto que a sua alternativa, <code>.forChild(...)</code>, configura para <em>lazy-loading</em>.</p><p><em>Eager-loading</em> significa que os caminhos carregam o seu conteúdo para a aplicação logo no início. <em>Lazy-loading</em> acontece por pedido. O foco deste artigo é o <em>eager-loading</em>. É a abordagem predefinida para carregar uma aplicação. A definição da classe RouterModule tem um aspeto semelhante ao próximo bloco de código.</p><pre><code class="language-typescript">@NgModule({
  // … montes de metadados ...
})
export class RouterModule {
  forRoot(routes: Routes) {
    // … configuração para caminhos eagerly loaded …
  }

  forChild(routes: Routes) {
    // … configuração para caminhos lazily loaded …
  }
}</code></pre><p>Não te preocupes com a configuração dos detalhes que o exemplo omite com comentários. Ter uma compreensão geral é suficiente por enquanto.</p><p>Observa como o AppRoutingModule importa o RouterModule enquanto também o exporta. Isto faz sentido visto que o AppRoutingModule é um módulo de recursos. Ele importa para o módulo raiz como um módulo de recursos. Ele expõe diretrizes RouterModule, interfaces e serviços para a árvore de componente raiz.</p><p>Isto explica a razão para o AppRoutingModule ter de exportar o RouterModule. Ele faz isto em prol da árvore de componentes subjacente da raiz do módulo. Ele precisa de ter acesso a essas funcionalidades de redirecionamento!</p><pre><code class="language-typescript">import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { AComponent } from './components/a/a.component';
import { BComponent } from './components/b/b.component';
import { AppRoutingModule } from './modules/app-routing/app-routing.module';

@NgModule({
  declarations: [
    AppComponent,
    AComponent,
    BComponent
  ],
  imports: [
    AppRoutingModule, // redirecionamento de módulo de funcionalidades
    BrowserModule
  ],
  providers: [],
  bootstrap: [ AppComponent ]
})
export class AppModule { }</code></pre><p>O token AppRoutingModule importa a partir do topo. O seu token é inserido na raiz do array de importação do módulo. A árvore de componente raiz pode agora utilizar a biblioteca RouterModule. Isto inclui as suas diretrizes, interfaces e serviços tal como já foi mencionado. Um grande agradecimento ao AppRoutingModule por exportar o RouterModule!</p><p>As funcionalidades do RouterModule vão dar jeito para os componentes da raiz. O HTML básico para o AppComponent utiliza uma diretriz: <code>router-outlet</code>.</p><pre><code class="language-html">&lt;!-- app.component.html --&gt;

&lt;ul&gt;
  &lt;!-- routerLink(s) aqui --&gt;
&lt;/ul&gt;
&lt;router-outlet&gt;&lt;/router-outlet&gt;
&lt;!-- conteúdo redirecionado é anexado aqui (DEPOIS DO ELEMENTO, NÃO DENTRO!) --&gt;</code></pre><p><code>routerLink</code> é uma diretriz de atributo do RouterModule. Vai ser anexada a cada elemento do <code>&lt;ul&gt;&lt;/ul&gt;</code> assim que os caminhos estejam configurados. <code>router-outlet</code> é uma diretriz de componente com um comportamento interessante. Funciona mais como um marcador para exibir conteúdo redirecionado. O conteúdo redirecionado é resultante da navegação para um caminho específico. Geralmente, isto significa um único componente, conforme configurado no AppRoutingModule.</p><p>O conteúdo redirecionado é renderizado logo após <code>&lt;router-outlet&gt;&lt;/router-outlet&gt;</code>. Nada é renderizado dentro dele. Isto não faz grande diferença. Dito isto, não esperes que o <code>router-outlet</code> se comporte como um recipiente para conteúdo redirecionado. É simplesmente um marcador para anexar conteúdo redirecionado ao Modelo de Objeto de Documento (DOM).</p><p>A primeira questão a ser abordada é que caminhos esta aplicação irá consumir? Bem, existem dois componentes: <code>AComponent</code> e <code>BComponent</code>. Cada um deve ter o seu próprio caminho. Estes podem renderizar a partir do <code>router-outlet</code> do AppComponent, dependendo da localização atual do caminho.</p><p>A localização do caminho (ou caminhos) define o que é anexado à <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin">origem de um website</a> (por exemplo, <a href="http://localhost:4200/">http://localhost:4200</a>), através de uma série de barras (<code>/</code>).</p><pre><code class="language-typescript">// … mesmas importações de antes …

const routes: Routes = [
  {
    path: 'A',
    component: AComponent
  },
  {
    path: 'B',
    component: BComponent
  }
];

@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule { }</code></pre><p><code>http://localhost:4200/A</code> renderiza AComponent a partir do <code>router-outlet</code> do AppComponent. <code>http://localhost:4200/B</code> renderiza BComponent. No entanto, precisas de uma maneira de encaminhar para essas localizações sem utilizar a barra de endereços. Uma aplicação não deve depender da barra de navegação de um browser para a navegação.</p><p><em>O<em> CSS (</em>do inglês, <em>Cascading Style</em>s<em>heets) </em>global suplementa o<em> HTML </em>abaixo dele<em>. </em>Um link de redirecionamento da aplicação deve ter uma boa aparência<em>. </em>O<em> CSS </em>abaixo também <em>é</em> aplicado<em> </em>a todos os outros exemplos<em>.</em></em></p><pre><code class="language-css">/* styles.css global */

ul li {
  cursor: pointer;
  display: inline-block;
  padding: 20px;
  margin: 5px;
  background-color: whitesmoke;
  border-radius: 5px;
  border: 1px solid black;
}

ul li:hover {
  background-color: lightgrey;
}</code></pre><pre><code class="language-html">&lt;!-- app.component.html --&gt;

&lt;ul&gt;
  &lt;li routerLink="/A"&gt;Vá para A!&lt;/li&gt;
  &lt;li routerLink="/B"&gt;Vá para B!&lt;/li&gt;
&lt;/ul&gt;
&lt;router-outlet&gt;&lt;/router-outlet&gt;</code></pre><p>Isto é redirecionamento básico! Clicar em qualquer um dos elementos routerLink encaminha para o endereço web. Isto redefine-o sem atualizar o browser. O <code>Router</code> do Angular mapeia o endereço encaminhado para o <code>Routes</code> configurado no AppRoutingModule. Ele faz a correspondência com a propriedade <code>path</code> de um único objeto <code>Route</code> dentro do array. A primeira correspondência vence sempre, por isso, caminhos de correspondência total devem estar no final do array <code>Routes</code>.</p><p>Caminhos de correspondência total previnem que a aplicação pare de funcionar se não conseguir corresponder a nenhum caminho atual. Isto pode acontecer a partir da barra de endereços, onde o utilizador pode escrever outro caminho. Para isso, o Angular fornece um valor de caminho <code>**</code>, que aceita todos os caminhos. Esse caminho geralmente renderiza um componente <code>PageNotFoundComponent</code>, que exibe "Error 404: Page not found" (Erro 404: página não encontrada).</p><pre><code class="language-typescript">// … PageNotFoundComponent importado juntamente com todo o resto …

const routes: Routes = [
  {
    path: 'A',
    component: AComponent
  },
  {
    path: 'B',
    component: BComponent
  },
  {
    path: '',
    redirectTo: 'A',
    pathMatch: 'full'
  },
  {
    path: '**',
    component: PageNotFoundComponent
  }
];</code></pre><p>O objeto <code>Route</code> que contém <code>redirectTo</code> impede que o PageNotFoundComponent renderize como resultado de <code>http://localhost:4200</code>. Este é o caminho principal da aplicação. Para corrigir isto, o <code>redirectTo</code> redireciona o caminho principal para <code>http://localhost:4200/A</code>. O <code>http://localhost:4200/A</code> torna-se indiretamente o novo caminho principal da aplicação.</p><p>O <code>pathMatch: 'full'</code> indica ao objeto <code>Route</code> para fazer correspondência com o caminho principal (<code>http://localhost:4200</code>). Isto corresponde a um caminho vazio.</p><p>Estes dois novos objetos <code>Route</code> ficam no final do array, visto que a primeira correspondência vence. O último elemento do array (<code>path: '**'</code>) corresponde sempre, por isso fica no final.</p><p>Existe mais uma coisa que vale a pena abordar antes de avançarmos. Como é que o utilizador sabe onde ele ou ela está na aplicação, em relação ao caminho atual? Claro que pode existir conteúdo específico para o caminho, mas como se supõe que um utilizador fará essa ligação? Deve existir algum tipo de destaque aplicado ao routerLinks. Deste modo, o utilizador saberá que caminho está ativo para a página da web fornecida.</p><p>Esta é uma solução simples. Quando clicas num elemento <code>routerLink</code>, o <code>Router</code> do Angular atribui-lhe <em><em>foc</em>o</em>. Esse foco pode acionar determinados estilos que fornecem feedback útil ao utilizador. A diretriz <code>routerLinkActive</code> pode rastrear este foco para o programador.</p><pre><code class="language-html">&lt;!-- app.component.html --&gt;

&lt;ul&gt;
  &lt;li routerLink="/A" routerLinkActive="active"&gt;Vá para A!&lt;/li&gt;
  &lt;li routerLink="/B" routerLinkActive="active"&gt;Vá para B!&lt;/li&gt;
&lt;/ul&gt;
&lt;router-outlet&gt;&lt;/router-outlet&gt;</code></pre><p>A atribuição correta de <code>routerLinkActive</code> representa uma string de classes. Este exemplo retrata apenas uma classe (<code>.active</code>), mas qualquer número de classes com espaço delimitado pode ser aplicado. Quando o <code>Router</code> atribui <em><em>foc</em>o</em> a um routerLink, as classes de espaço delimitado são aplicadas ao elemento anfitrião. Quando o foco desaparece, as classes são removidas automaticamente.</p><pre><code class="language-css">/* styles.css global */

.active {
  background-color: lightgrey !important;
}</code></pre><p>Os utilizadores podem agora facilmente reconhecer como o caminho atual e o conteúdo da página coincidem. O destaque <code>lightgrey</code> aplica-se à correspondência do routerLink com o caminho atual. <code>!important</code> garante que o destaque se sobrepõe a estilo em linha.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Hooks do ciclo de vida do Angular: ngOnChanges, ngOnInit e muito mais ]]>
                </title>
                <description>
                    <![CDATA[ Por que precisamos de hooks do ciclo de vida? Os frameworks modernos de front-end movem a aplicação de um estado para outro. Os dados alimentam essas atualizações. Essas tecnologias interagem com os dados que, por sua vez, fazem a transição do estado. A cada mudança de estado, há muitos momentos ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/hooks-do-ciclo-de-vida-do-angular-ngonchanges-ngoninit-e-muito-mais/</link>
                <guid isPermaLink="false">648f1ed33f8119067d31ef85</guid>
                
                    <category>
                        <![CDATA[ Angular ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Carlos Silva. ]]>
                </dc:creator>
                <pubDate>Wed, 05 Jul 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/07/5f9c9d66740569d1a4ca378c.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/angular-lifecycle-hooks/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Angular Lifecycle Hooks: ngOnChanges, ngOnInit, and more</a>
      </p><h3 id="por-que-precisamos-de-hooks-do-ciclo-de-vida"><strong>Por que precisamos de <em>hooks </em>do ciclo de vida?</strong></h3><p>Os <em>frameworks</em> modernos de <em>front-end</em> movem a aplicação de um estado para outro. Os dados alimentam essas atualizações. Essas tecnologias interagem com os dados que, por sua vez, fazem a transição do estado. A cada mudança de estado, há muitos momentos específicos em que determinados ativos ficam disponíveis.</p><p>Em um momento, o modelo pode estar pronto. Em outro, os dados terão terminado de ser carregados. A programação de cada exemplo requer um meio de detecção. Os <em>hooks </em>de ciclo de vida atendem a essa necessidade. Os <em>frameworks</em> modernos de <em>front-end</em> vêm com uma variedade de <em>hooks</em> de ciclo de vida. O Angular não é uma exceção.</p><h2 id="hooks-de-ciclo-de-vida-explicados"><strong><em>Hooks </em>de ciclo de vida explicados</strong></h2><p>Os <em>hooks </em>de ciclo de vida são métodos programados para serem executados em determinado momento. Eles diferem em quando e por que são executados. A detecção de alterações aciona esses métodos. Eles são executados de acordo com as condições do ciclo atual. O Angular executa a detecção de alterações constantemente em seus dados. Os <em>hooks </em>de ciclo de vida ajudam a gerenciar seus efeitos.</p><p>Um aspecto importante desses <em>hooks </em>é sua ordem de execução. Ela nunca muda. Eles são executados com base em uma série previsível de eventos de carregamento produzidos a partir de um ciclo de detecção. Isso os torna previsíveis.</p><p>Alguns ativos só estão disponíveis após a execução de um determinado <em>hook</em>. Obviamente, um <em>hook </em>só é executado sob determinadas condições definidas no ciclo de detecção de alterações atual.</p><p>Este artigo apresenta os <em>hooks </em>de ciclo de vida na ordem de sua execução (se todos forem executados). Certas condições merecem a ativação de um <em>hook</em>. Há alguns que são executados apenas uma vez, após a inicialização do componente.</p><p>Todos os métodos do ciclo de vida estão disponíveis em <code>@angular/core</code>. Embora não seja obrigatório, o Angular <a href="https://angular.io/guide/lifecycle-hooks#interfaces-are-optional-technically">recomenda a implementação de todos os <em>hooks</em></a><em> </em>(texto em inglês). Essa prática resulta em mensagens de erro mais relacionadas ao componente.</p><h2 id="ordem-de-execu-o-dos-hooks-de-ciclo-de-vida"><strong>Ordem de execução dos <em>hooks </em>de ciclo de vida</strong></h2><h3 id="ngonchanges"><strong>ngOnChanges</strong></h3><p>O <code>ngOnChanges</code> é acionado após a modificação dos membros da classe vinculada <code>@Input</code>. Os dados vinculados pelo decorador <code>@Input()</code> são provenientes de uma fonte externa. Quando a fonte externa altera esses dados de maneira detectável, eles passam novamente pela propriedade <code>@Input</code>.</p><p>Com essa atualização, o <code>ngOnChanges</code> é acionado imediatamente. Ele também é acionado na inicialização dos dados de entrada. O <em>hook </em>recebe um parâmetro opcional do tipo <code>SimpleChanges</code>. Esse valor contém informações sobre as propriedades de limite de entrada alteradas.</p><pre><code class="language-typescript">import { Component, Input, OnChanges } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `
  &lt;h3&gt;Child Component&lt;/h3&gt;
  &lt;p&gt;TICKS: {{ lifecycleTicks }}&lt;/p&gt;
  &lt;p&gt;DATA: {{ data }}&lt;/p&gt;
  `
})
export class ChildComponent implements OnChanges {
  @Input() data: string;
  lifecycleTicks: number = 0;

  ngOnChanges() {
    this.lifecycleTicks++;
  }
}

@Component({
  selector: 'app-parent',
  template: `
  &lt;h1&gt;ngOnChanges Example&lt;/h1&gt;
  &lt;app-child [data]="arbitraryData"&gt;&lt;/app-child&gt;
  `
})
export class ParentComponent {
  arbitraryData: string = 'initial';

  constructor() {
    setTimeout(() =&gt; {
      this.arbitraryData = 'final';
    }, 5000);
  }
}</code></pre><p><strong>Resumo<strong><strong><strong>:</strong></strong></strong></strong> o <code>ParentComponent</code> (componente pai) vincula os dados de entrada ao <code>ChildComponent</code> (componente filho). O componente recebe esses dados por meio de sua propriedade <code>@Input</code> e <code>ngOnChanges</code> é acionado. Após cinco segundos, a chamada de retorno <code>setTimeout</code> é acionada. O <code>ParentComponent</code> altera a fonte de dados da propriedade do limite de entrada do <code>ChildComponent</code>. Os novos dados fluem pela propriedade de entrada. O <code>ngOnChanges</code> é acionado mais uma vez.</p><h3 id="ngoninit"><strong>ngOnInit</strong></h3><p>O <code>ngOnInit</code> é acionado uma vez na inicialização das propriedades vinculadas à entrada (<code>@Input</code>) de um componente. O próximo exemplo será semelhante ao anterior. O <em>hook</em> não é acionado quando o <code>ChildComponent</code> recebe os dados de entrada. Em vez disso, ele é acionado logo após os dados serem renderizados no modelo <code>ChildComponent</code>.</p><pre><code class="language-typescript">import { Component, Input, OnInit } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `
  &lt;h3&gt;Child Component&lt;/h3&gt;
  &lt;p&gt;TICKS: {{ lifecycleTicks }}&lt;/p&gt;
  &lt;p&gt;DATA: {{ data }}&lt;/p&gt;
  `
})
export class ChildComponent implements OnInit {
  @Input() data: string;
  lifecycleTicks: number = 0;

  ngOnInit() {
    this.lifecycleTicks++;
  }
}

@Component({
  selector: 'app-parent',
  template: `
  &lt;h1&gt;ngOnInit Example&lt;/h1&gt;
  &lt;app-child [data]="arbitraryData"&gt;&lt;/app-child&gt;
  `
})
export class ParentComponent {
  arbitraryData: string = 'initial';

  constructor() {
    setTimeout(() =&gt; {
      this.arbitraryData = 'final';
    }, 5000);
  }
}</code></pre><p><strong>Resumo<strong><strong><strong>:</strong></strong></strong></strong> o <code>ParentComponent</code> vincula os dados de entrada ao <code>ChildComponent</code>. O ChildComponent recebe esses dados por meio de sua propriedade <code>@Input</code>. Os dados são renderizados para o modelo e o <code>ngOnInit</code> é acionado. Após cinco segundos, a chamada de retorno <code>setTimeout</code> é acionada. O ParentComponent muda a fonte de dados da propriedade vinculada à entrada de ChildComponent e ngOnInit <strong>NÃO É ACIONADO</strong>.</p><p><code>ngOnInit</code> é um <em>hook </em>de uso único. A inicialização é sua única preocupação.</p><h3 id="ngdocheck"><strong>ngDoCheck</strong></h3><p>O <code>ngDoCheck</code> é acionado a cada ciclo de detecção de alterações. O Angular executa a detecção de alterações com frequência. O desempenho de qualquer ação fará com que ele entre em ciclo e <code>ngDoCheck</code> é acionado com esses ciclos. Use-o com cautela. Ele pode criar problemas de desempenho quando implementado incorretamente.</p><p><code>ngDoCheck</code> permite que os desenvolvedores verifiquem seus dados manualmente. Eles podem acionar uma nova data de aplicação condicionalmente. Em conjunto com <code>ChangeDetectorRef</code>, os desenvolvedores podem criar suas próprias verificações para detecção de alterações.</p><pre><code class="language-typescript">import { Component, DoCheck, ChangeDetectorRef } from '@angular/core';

@Component({
  selector: 'app-example',
  template: `
  &lt;h1&gt;ngDoCheck Example&lt;/h1&gt;
  &lt;p&gt;DATA: {{ data[data.length - 1] }}&lt;/p&gt;
  `
})
export class ExampleComponent implements DoCheck {
  lifecycleTicks: number = 0;
  oldTheData: string;
  data: string[] = ['initial'];

  constructor(private changeDetector: ChangeDetectorRef) {
    this.changeDetector.detach(); // lets the class perform its own change detection

    setTimeout(() =&gt; {
      this.oldTheData = 'final'; // intentional error
      this.data.push('intermediate');
    }, 3000);

    setTimeout(() =&gt; {
      this.data.push('final');
      this.changeDetector.markForCheck();
    }, 6000);
  }

  ngDoCheck() {
    console.log(++this.lifecycleTicks);

    if (this.data[this.data.length - 1] !== this.oldTheData) {
      this.changeDetector.detectChanges();
    }
  }
}</code></pre><p>Preste atenção no console e contrate-o com o que aparece na tela. Os dados progridem até "intermediário" antes de congelar. Três rodadas de detecção de mudanças ocorrem durante esse período, conforme indicado no console. Mais uma rodada de detecção de alterações ocorre quando 'final' é empurrado para o final de <code>this.data</code>. Em seguida, ocorre uma última rodada de detecção de mudanças. A avaliação da instrução <code>if</code> determina que não são necessárias atualizações na exibição.</p><p><strong>Resumo<strong><strong><strong>:</strong></strong></strong></strong> a classe é exemplificada após duas rodadas de detecção de alterações. O construtor da classe inicia o <code>setTimeout</code> duas vezes. Após três segundos, o primeiro <code>setTimeout</code> aciona a detecção de alterações e o <code>ngDoCheck</code> marca a tela para uma atualização. Três segundos depois, o segundo <code>setTimeout</code> aciona a detecção de alterações. Não são necessárias atualizações de visualização de acordo com a avaliação de <code>ngDoCheck</code>.</p><h3 id="aviso">Aviso</h3><p>Antes de continuar, aprenda a diferença entre o DOM de conteúdo e o DOM de visualização (DOM significa Modelo de Objeto do Documento).</p><p>O DOM de conteúdo define o <code>innerHTML</code> dos elementos da diretiva. Por outro lado, o DOM de visualização é o modelo de um componente, excluindo qualquer modelo HTML agrupado em uma diretiva. Para entender melhor, consulte <a href="http://blog.mgechev.com/2016/01/23/angular2-viewchildren-contentchildren-difference-viewproviders">este artigo do blog</a> (texto em inglês) do autor Minko Gechev.</p><h3 id="ngaftercontentinit"><strong>ngAfterContentInit</strong></h3><p><code>ngAfterContentInit</code> é acionado depois que o DOM do conteúdo do componente é inicializado (carregado pela primeira vez). Esperar por pesquisas (do inglês, <em>queries</em>) de <code>@ContentChild(ren)</code> é o principal caso de uso do <em>hook</em>.</p><p>As pesquisas de <code>@ContentChild(ren)</code> produzem referências de elementos para o DOM de conteúdo. Desse modo, eles não ficam disponíveis até que o DOM do conteúdo seja carregado. Por isso, o <code>ngAfterContentInit</code> e seu equivalente <code>ngAfterContentChecked</code> são usados.</p><pre><code class="language-typescript">import { Component, ContentChild, AfterContentInit, ElementRef, Renderer2 } from '@angular/core';

@Component({
  selector: 'app-c',
  template: `
  &lt;p&gt;I am C.&lt;/p&gt;
  &lt;p&gt;Hello World!&lt;/p&gt;
  `
})
export class CComponent { }

@Component({
  selector: 'app-b',
  template: `
  &lt;p&gt;I am B.&lt;/p&gt;
  &lt;ng-content&gt;&lt;/ng-content&gt;
  `
})
export class BComponent implements AfterContentInit {
  @ContentChild("BHeader", { read: ElementRef }) hRef: ElementRef;
  @ContentChild(CComponent, { read: ElementRef }) cRef: ElementRef;

  constructor(private renderer: Renderer2) { }

  ngAfterContentInit() {
    this.renderer.setStyle(this.hRef.nativeElement, 'background-color', 'yellow')

    this.renderer.setStyle(this.cRef.nativeElement.children.item(0), 'background-color', 'pink');
    this.renderer.setStyle(this.cRef.nativeElement.children.item(1), 'background-color', 'red');
  }
}

@Component({
  selector: 'app-a',
  template: `
  &lt;h1&gt;ngAfterContentInit Example&lt;/h1&gt;
  &lt;p&gt;I am A.&lt;/p&gt;
  &lt;app-b&gt;
    &lt;h3 #BHeader&gt;BComponent Content DOM&lt;/h3&gt;
    &lt;app-c&gt;&lt;/app-c&gt;
  &lt;/app-b&gt;
  `
})
export class AComponent { }</code></pre><p>Os resultados da pesquisa de <code>@ContentChild</code> estão disponíveis em <code>ngAfterContentInit</code>. O <code>Renderer2</code> atualiza o DOM de conteúdo do <code>BComponent</code>, que contém uma tag <code>h3</code> e o <code>CComponent</code>. Esse é um exemplo comum de <a href="https://alligator.io/angular/content-projection-angular">projeção de conteúdo</a> (texto em inglês).</p><p><strong>Resumo<strong><strong><strong>:</strong></strong></strong></strong> a renderização começa com o <code>AComponent</code>. Para concluir, o <code>AComponent</code> deve renderizar o <code>BComponent</code>. O <code>BComponent</code> projeta o conteúdo agrupado em seu elemento por meio do elemento <code>&lt;ng-content&gt;&lt;/ng-content&gt;</code>. O <code>CComponent</code> faz parte do conteúdo projetado. O conteúdo projetado termina de ser renderizado. O <code>ngAfterContentInit</code> é acionado. O <code>BComponent</code> termina a renderização. O <code>AComponent</code> termina a renderização. <code>ngAfterContentInit</code> não será acionado novamente.</p><h3 id="ngaftercontentchecked"><strong>ngAfterContentChecked</strong></h3><p>O <code>ngAfterContentChecked</code> é acionado após cada ciclo de detecção de alterações direcionado ao DOM de conteúdo. Isso permite que os desenvolvedores facilitem o modo como o DOM do conteúdo reage à detecção de alterações. O <code>ngAfterContentChecked</code> pode ser acionado com frequência e causar problemas de desempenho se for implementado incorretamente.</p><p>O <code>ngAfterContentChecked</code> também é acionado durante os estágios de inicialização de um componente. Ele vem logo após <code>ngAfterContentInit</code>.</p><pre><code class="language-typescript">import { Component, ContentChild, AfterContentChecked, ElementRef, Renderer2 } from '@angular/core';

@Component({
  selector: 'app-c',
  template: `
  &lt;p&gt;I am C.&lt;/p&gt;
  &lt;p&gt;Hello World!&lt;/p&gt;
  `
})
export class CComponent { }

@Component({
  selector: 'app-b',
  template: `
  &lt;p&gt;I am B.&lt;/p&gt;
  &lt;button (click)="$event"&gt;CLICK&lt;/button&gt;
  &lt;ng-content&gt;&lt;/ng-content&gt;
  `
})
export class BComponent implements AfterContentChecked {
  @ContentChild("BHeader", { read: ElementRef }) hRef: ElementRef;
  @ContentChild(CComponent, { read: ElementRef }) cRef: ElementRef;

  constructor(private renderer: Renderer2) { }

  randomRGB(): string {
    return `rgb(${Math.floor(Math.random() * 256)},
    ${Math.floor(Math.random() * 256)},
    ${Math.floor(Math.random() * 256)})`;
  }

  ngAfterContentChecked() {
    this.renderer.setStyle(this.hRef.nativeElement, 'background-color', this.randomRGB());
    this.renderer.setStyle(this.cRef.nativeElement.children.item(0), 'background-color', this.randomRGB());
    this.renderer.setStyle(this.cRef.nativeElement.children.item(1), 'background-color', this.randomRGB());
  }
}

@Component({
  selector: 'app-a',
  template: `
  &lt;h1&gt;ngAfterContentChecked Example&lt;/h1&gt;
  &lt;p&gt;I am A.&lt;/p&gt;
  &lt;app-b&gt;
    &lt;h3 #BHeader&gt;BComponent Content DOM&lt;/h3&gt;
    &lt;app-c&gt;&lt;/app-c&gt;
  &lt;/app-b&gt;
  `
})
export class AComponent { }</code></pre><p>Ele não difere muito do <code>ngAfterContentInit</code>. Um mero <code>&lt;button&gt;&lt;/button&gt;</code> foi adicionado ao <code>BComponent</code>. Clicar nele causa um loop de detecção de alterações. Isso ativa o gancho, conforme indicado pela aleatoriedade da <code>cor de fundo</code>.</p><p><strong>Resumo<strong><strong><strong>:</strong></strong></strong></strong> a renderização começa com o <code>AComponent</code>. Para concluir, o <code>AComponent</code> deve renderizar o <code>BComponent</code>. O <code>BComponent</code> projeta o conteúdo agrupado em seu elemento por meio do elemento <code>&lt;ng-content&gt;&lt;/ng-content&gt;</code>. O <code>CComponent</code> faz parte do conteúdo projetado. O conteúdo projetado termina de ser renderizado. <code>ngAfterContentChecked</code> é acionado. O <code>BComponent</code> termina a renderização. <code>AComponent</code> termina a renderização. O <code>ngAfterContentChecked</code> pode ser acionado novamente por meio da detecção de alterações.</p><h3 id="ngafterviewinit"><strong>ngAfterViewInit</strong></h3><p>O <code>ngAfterViewInit</code> é acionado uma vez após a conclusão da inicialização do DOM de visualização. A visualização sempre é carregada logo após o conteúdo. <code>ngAfterViewInit</code> aguarda a resolução das pesquisas <code>@ViewChild(ren)</code>. Esses elementos são consultados na mesma visualização do componente.</p><p>No exemplo abaixo, o título <code>h3</code> de <code>BComponent</code> é pesquisado. <code>ngAfterViewInit</code> é executado assim que os resultados da pesquisa estão disponíveis.</p><pre><code class="language-typescript">import { Component, ViewChild, AfterViewInit, ElementRef, Renderer2 } from '@angular/core';

@Component({
  selector: 'app-c',
  template: `
  &lt;p&gt;I am C.&lt;/p&gt;
  &lt;p&gt;Hello World!&lt;/p&gt;
  `
})
export class CComponent { }

@Component({
  selector: 'app-b',
  template: `
  &lt;p #BStatement&gt;I am B.&lt;/p&gt;
  &lt;ng-content&gt;&lt;/ng-content&gt;
  `
})
export class BComponent implements AfterViewInit {
  @ViewChild("BStatement", { read: ElementRef }) pStmt: ElementRef;

  constructor(private renderer: Renderer2) { }

  ngAfterViewInit() {
    this.renderer.setStyle(this.pStmt.nativeElement, 'background-color', 'yellow');
  }
}

@Component({
  selector: 'app-a',
  template: `
  &lt;h1&gt;ngAfterViewInit Example&lt;/h1&gt;
  &lt;p&gt;I am A.&lt;/p&gt;
  &lt;app-b&gt;
    &lt;h3&gt;BComponent Content DOM&lt;/h3&gt;
    &lt;app-c&gt;&lt;/app-c&gt;
  &lt;/app-b&gt;
  `
})
export class AComponent { }</code></pre><p><code>Renderer2</code> altera a cor de fundo do título de <code>BComponent</code>. Isso indica que o elemento de visualização foi pesquisado com sucesso graças ao <code>ngAfterViewInit</code>.</p><p><strong>Resumo<strong><strong><strong>:</strong></strong></strong></strong> a renderização começa com o <code>AComponent</code>. Para concluir, o <code>AComponent</code> deve renderizar o <code>BComponent</code>. O <code>BComponent</code> projeta o conteúdo agrupado em seu elemento por meio do elemento <code>&lt;ng-content&gt;&lt;/ng-content&gt;</code>. <code>CComponent</code> faz parte do conteúdo projetado. O <code>BComponent</code> termina a renderização. O <code>ngAfterViewInit</code> é acionado. <code>AComponent</code> termina a renderização. <code>ngAfterViewInit</code> não será acionado novamente.</p><h3 id="ngafterviewchecked"><strong>ngAfterViewChecked</strong></h3><p>O <code>ngAfterViewChecked</code> é acionado após qualquer ciclo de detecção de alterações que tenha como alvo a visualização do componente. O <em>hook </em><code>ngAfterViewChecked</code> permite que os desenvolvedores facilitem o modo como a detecção de alterações afeta o DOM de visualização.</p><pre><code class="language-typescript">import { Component, ViewChild, AfterViewChecked, ElementRef, Renderer2 } from '@angular/core';

@Component({
  selector: 'app-c',
  template: `
  &lt;p&gt;I am C.&lt;/p&gt;
  &lt;p&gt;Hello World!&lt;/p&gt;
  `
})
export class CComponent { }

@Component({
  selector: 'app-b',
  template: `
  &lt;p #BStatement&gt;I am B.&lt;/p&gt;
  &lt;button (click)="$event"&gt;CLICK&lt;/button&gt;
  &lt;ng-content&gt;&lt;/ng-content&gt;
  `
})
export class BComponent implements AfterViewChecked {
  @ViewChild("BStatement", { read: ElementRef }) pStmt: ElementRef;

  constructor(private renderer: Renderer2) { }

  randomRGB(): string {
    return `rgb(${Math.floor(Math.random() * 256)},
    ${Math.floor(Math.random() * 256)},
    ${Math.floor(Math.random() * 256)})`;
  }

  ngAfterViewChecked() {
    this.renderer.setStyle(this.pStmt.nativeElement, 'background-color', this.randomRGB());
  }
}

@Component({
  selector: 'app-a',
  template: `
  &lt;h1&gt;ngAfterViewChecked Example&lt;/h1&gt;
  &lt;p&gt;I am A.&lt;/p&gt;
  &lt;app-b&gt;
    &lt;h3&gt;BComponent Content DOM&lt;/h3&gt;
    &lt;app-c&gt;&lt;/app-c&gt;
  &lt;/app-b&gt;
  `
})
export class AComponent { }</code></pre><p><strong>Resumo<strong><strong><strong>:</strong></strong></strong></strong> a renderização começa com o <code>AComponent</code>. Para concluir, o <code>AComponent</code> deve renderizar o <code>BComponent</code>. O <code>BComponent</code> projeta o conteúdo agrupado em seu elemento por meio do elemento <code>&lt;ng-content&gt;&lt;/ng-content&gt;</code>. <code>CComponent</code> faz parte do conteúdo projetado. O conteúdo projetado termina de ser renderizado. O <code>BComponent</code> termina a renderização. <code>ngAfterViewChecked</code> é acionado. O <code>AComponent</code> termina a renderização. O <code>ngAfterViewChecked</code> pode ser acionado novamente por meio da detecção de alterações.</p><p>Clicar no elemento <code>&lt;button&gt;&lt;/button&gt;</code> inicia uma rodada de detecção de alterações. O <code>ngAfterContentChecked</code> dispara e randomiza a <code>cor de fundo</code> dos elementos consultados a cada clique no botão.</p><h3 id="ngondestroy"><strong>ngOnDestroy</strong></h3><p><code>ngOnDestroy</code> é acionado quando um componente é removido da visualização e do DOM subsequente. Esse <em>hook</em> oferece uma chance de reparar quaisquer pontas soltas antes da exclusão de um componente.</p><pre><code class="language-typescript">import { Directive, Component, OnDestroy } from '@angular/core';

@Directive({
  selector: '[appDestroyListener]'
})
export class DestroyListenerDirective implements OnDestroy {
  ngOnDestroy() {
    console.log("Goodbye World!");
  }
}

@Component({
  selector: 'app-example',
  template: `
  &lt;h1&gt;ngOnDestroy Example&lt;/h1&gt;
  &lt;button (click)="toggleDestroy()"&gt;TOGGLE DESTROY&lt;/button&gt;
  &lt;p appDestroyListener *ngIf="destroy"&gt;I can be destroyed!&lt;/p&gt;
  `
})
export class ExampleComponent {
  destroy: boolean = true;

  toggleDestroy() {
    this.destroy = !this.destroy;
  }
}</code></pre><p><strong>Resumo<strong><strong><strong>:</strong></strong></strong></strong> o botão é clicado. O membro <code>destroy</code> de <code>ExampleComponent</code> alterna para <code>false</code>. A instrução estrutural <code>*ngIf</code> é avaliada como falsa. <code>ngOnDestroy</code> é acionado. O <code>*ngIf</code> remove o<em> </em><code>&lt;p&gt;&lt;/p&gt;</code> que servia como seu <em>host</em>. Esse processo se repete qualquer número de vezes que você clicar no botão para alternar <code>destroy</code> para <code>false</code>.</p><h2 id="conclus-o"><strong>Conclusão</strong></h2><p>Lembre-se de que determinadas condições devem ser atendidas para cada <em>hook</em>. Eles sempre serão executados em ordem sequencial, independentemente. Isso torna os <em>hooks </em>previsíveis o suficiente para serem usados, mesmo que alguns não sejam executados.</p><p>Com os <em>hooks </em>de ciclo de vida, é fácil prever o momento de execução de uma classe. Eles permitem que os desenvolvedores acompanhem onde a detecção de alterações está ocorrendo e como a aplicação deve reagir. Eles ficam parados em códigos que exigem dependências baseadas em carregamentos disponíveis somente após algum tempo.</p><p>O ciclo de vida do componente caracteriza os <em>frameworks</em> modernos de <em>front-end</em>. O Angular organiza seu ciclo de vida fornecendo os <em>hooks </em>mencionados acima.</p><h2 id="recursos-em-ingl-s-">Recursos<strong> (em inglês)</strong></h2><ul><li><a href="https://angular.io/guide/lifecycle-hooks">Equipe do Angular. "Lifecycle Hooks". <em><em>Google</em></em>. Acessado em 2 Junho de 2018</a></li><li><a href="http://blog.mgechev.com/2016/01/23/angular2-viewchildren-contentchildren-difference-viewproviders">Gechev, Minko. "ViewChildren and ContentChildren in Angular". Acessado em 2 Junho de 2018</a></li></ul><h2 id="outras-fontes-em-ingl-s-"><strong>Outras fontes (em inglês)</strong></h2><ul><li><a href="https://angular.io/docs">Documentação do Angular</a></li><li><a href="https://github.com/angular/angular">Repositório do GitHub do Angular</a></li><li><a href="https://angular.io/guide/lifecycle-hooks"><em>Hooks </em>do ciclo de vida em detalhes</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Lazy loading no Angular – um guia para iniciantes sobre os NgModules ]]>
                </title>
                <description>
                    <![CDATA[ O que é lazy loading? O lazy loading (algo como "carregamento lento", em português) é o processo de carregamento de componentes, módulos ou outros ativos de um site, conforme necessário. Como o Angular cria uma SPA (Aplicação de Página Única) [https://en.wikipedia.org/wiki/Single-page_application#:~:text=From%20Wikipedia%2C%20the%20free%20encyclopedia,browser%20loading%20entire%20new%20pages.] , todos os seus componentes são carregados de uma ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/lazy-loading-no-angular-um-guia-para-iniciantes-sobre-os-ngmodules/</link>
                <guid isPermaLink="false">6488e5f8d1454605b613f0f3</guid>
                
                    <category>
                        <![CDATA[ Angular ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Carlos Silva. ]]>
                </dc:creator>
                <pubDate>Mon, 03 Jul 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/cat-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/lazy-loading-in-angular-intro-to-ngmodules/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Lazy Loading in Angular – A Beginner's Guide to NgModules</a>
      </p><h2 id="o-que-lazy-loading">O que é <em>lazy loading</em><strong>?</strong></h2><p>O <em>lazy loading</em> (algo como "carregamento lento", em português) é o processo de carregamento de componentes, módulos ou outros ativos de um site, conforme necessário.</p><p>Como o Angular cria uma <a href="https://en.wikipedia.org/wiki/Single-page_application#:~:text=From%20Wikipedia%2C%20the%20free%20encyclopedia,browser%20loading%20entire%20new%20pages.">SPA (Aplicação de Página Única)</a>, todos os seus componentes são carregados de uma só vez. Isso significa que muitas bibliotecas ou módulos desnecessários também podem ser carregados.</p><p>Para uma aplicação pequena, não há problema. Porém, à medida que a aplicação cresce, o tempo de carregamento aumentará se tudo for carregado de uma vez. O lazy loading permite que o Angular carregue componentes e módulos como e quando eles forem necessários.</p><p>Em primeiro lugar, para entender como o <em>lazy loading</em> funciona no Angular, precisamos entender os blocos de construção básicos da estrutura: os <strong>NgModules</strong>.</p><h2 id="o-que-s-o-os-ngmodules"><strong>O que são os </strong>NgModules<strong>?</strong></h2><p>Bibliotecas do Angular, como RouterModule, BrowserModule e FormsModule são conhecidas como <strong>NgModules</strong>. <a href="https://material.angular.io/">Material Angular</a>, que é uma ferramenta de terceiros, também é um tipo de NgModule.</p><p>Os NgModules consistem em arquivos e códigos relacionados a um domínio específico ou que têm um conjunto semelhante de funcionalidades.</p><p>Um arquivo NgModule típico declara componentes, instruções, <em>pipes</em> e serviços. Ele também pode importar outros módulos que são necessários no módulo atual.</p><p>Uma das vantagens importantes dos NgModules é que eles podem ser carregados lentamente. Vamos dar uma olhada em como podemos configurar o carregamento lento.</p><p>Você pode <a href="https://www.freecodecamp.org/news/lazy-loading-in-angular-intro-to-ngmodules/#root-module">verificar abaixo</a> para ver como é um arquivo NgModule básico.</p><h2 id="como-criar-ngmodules"><strong>Como criar NgModules</strong></h2><p>Neste tutorial, criaremos dois módulos, <em><em><em><em>Módulo</em></em></em> <em><em>A</em></em></em> e <em><em><em>Módulo B</em></em></em>, que serão carregados lentamente. Na tela principal, teremos dois botões para carregar cada módulo de maneira lenta.</p><h3 id="crie-o-projeto"><strong>Crie o projeto</strong></h3><p>Crie um projeto do Angular chamado <em><em><em><em>lazy-load-demo</em></em></em></em> executando o comando abaixo:</p><pre><code>ng new lazy-load-demo --routing --style css
code lazy-load-demo
</code></pre><p>Aqui, estamos criando um novo projeto com roteamento. Além disso, mencionamos o formato da folha de estilo para CSS. O segundo comando abre seu projeto no VS Code.</p><h3 id="m-dulo-root"><strong>Módulo Root</strong></h3><p>Por padrão, um módulo raiz ou módulo de aplicação é criado em <em><em><em><em>/src/app</em></em></em></em>. Abaixo está o arquivo NgModule que é criado.</p><pre><code>import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
</code></pre><p>Primeiro, importamos todos os módulos e componentes necessários.</p><p>Depois disso, o decorador <strong><strong><strong><strong><code>@NgModule</code></strong></strong></strong></strong> declara que a classe AppModule é um tipo de NgModule. O decorador aceita <em><em><em>declarações, importações, provedores </em></em></em>e<em><em><em><em> bootstrap. </em></em></em></em>Aqui estão as descrições de cada um deles:</p><ul><li><strong><strong><strong><strong>decla</strong></strong></strong>raçõe<strong><strong><strong>s</strong></strong></strong></strong>: os componentes deste módulo.</li><li><strong><strong><strong><strong>i</strong></strong></strong>mportações</strong>: os módulos que são exigidos pelo módulo atual.</li><li><strong><strong><strong><strong>prov</strong></strong></strong>edores</strong>: os provedores de serviços, se houver.</li><li><strong><strong><strong><strong>bootstrap</strong></strong></strong></strong>: o componente <em><em><em><em>root</em></em></em></em> que o Angular cria e insere na página da Web do host <code>index.html</code>.</li></ul><h3 id="tela-principal"><strong>Tela principal</strong></h3><p>A tela principal terá dois botões: <strong> Load Module<strong><strong><strong> A </strong></strong></strong></strong>e<strong><strong><strong> </strong></strong>Load Module B<strong><strong>.</strong></strong></strong> Como o nome sugere (Carregar o módulo A e Carregar o módulo B, respectivamente), clicar nesses botões carregará lentamente cada módulo.</p><p>Para isso, substitua seu arquivo <em><em><em><em>app.component.html</em></em></em></em> pelo conteúdo abaixo.</p><pre><code>&lt;button style="padding: 20px; color: white; background-color: green;" routerLink="a"&gt;Load Module A&lt;/button&gt;
&lt;button style="padding: 20px; color: white; background-color: blue;" routerLink="b"&gt;Load Module B&lt;/button&gt;
&lt;router-outlet&gt;&lt;/router-outlet&gt;
</code></pre><p>Vamos definir os módulos para as rotas <em><em><em><em>a </em></em></em></em>e <em><em><em><em>b</em></em></em></em>.</p><h3 id="m-dulos-de-carregamento-lento"><strong>Módulos de carregamento lento</strong></h3><p>Para criar módulos carregados de modo lento, execute os comandos abaixo:</p><pre><code>ng generate module modulea --route a --module app.module
ng generate module moduleb --route b --module app.module
</code></pre><p>Os comandos gerarão duas pastas, chamadas <strong><strong><strong><strong>modulea</strong></strong></strong></strong> e <strong><strong><strong><strong>moduleb</strong></strong></strong></strong>. Cada pasta conterá seus próprios arquivos <em><em><em>module.ts</em></em></em>,<em><em><em> routing.ts </em></em></em> e <em><em><em>component</em></em></em>.</p><p>Se você verificar seu <em><em><em><em>app-routing.module.ts</em></em></em></em>, verá o código abaixo para as rotas:</p><pre><code>const routes: Routes = [
  { path: 'a', loadChildren: () =&gt; import('./modulea/modulea.module').then(m =&gt; m.ModuleaModule) },
  { path: 'b', loadChildren: () =&gt; import('./moduleb/moduleb.module').then(m =&gt; m.ModulebModule) }
];
</code></pre><p>Isso implica que, quando a rota <em><em><em><em>a</em></em></em></em> ou <em><em><em><em>b </em></em></em></em>é visitada, carrega seus respectivos módulos de maneira lenta.</p><p>Ao executar o projeto com <strong><strong><strong><strong>ng serve</strong></strong></strong></strong>, você verá a tela abaixo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/Screenshot-2021-04-25-at-11.18.55-PM.png" class="kg-image" alt="Screenshot-2021-04-25-at-11.18.55-PM" width="434" height="210" loading="lazy"><figcaption>Página inicial</figcaption></figure><p>Ao clicar no botão <em><em><em><em>Load Module A</em></em></em></em>, você será direcionado para a página <em><em><em><em>a</em></em></em></em>. Esta é a aparência da sua tela:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/Screenshot-2021-04-25-at-11.18.14-PM.png" class="kg-image" alt="Screenshot-2021-04-25-at-11.18.14-PM" width="483" height="245" loading="lazy"><figcaption>Módulo A carregado em lazy loading</figcaption></figure><p>Você deverá ver uma tela semelhante que diz <strong><strong><strong><strong>moduleb </strong></strong></strong>works<strong><strong><strong>! </strong></strong></strong></strong> quando clicar em <em><em><em>Load Module B.</em></em></em></p><h2 id="como-verificar-se-o-lazy-loading-funcionou"><strong>Como verificar se o <em>lazy loading </em>funcionou</strong></h2><p>Para verificar se os arquivos foram carregados, abra as ferramentas de desenvolvedor pressionando F12. Depois disso, visite a aba <em><em><em><em>Network</em></em></em></em>, como pode ser visto na captura de tela abaixo. Quando você atualizar a página, ela mostrará alguns arquivos que foram solicitados.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/Network-Tab-1.jpg" class="kg-image" alt="Network-Tab-1" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/Network-Tab-1.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/06/Network-Tab-1.jpg 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2023/06/Network-Tab-1.jpg 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/Network-Tab-1.jpg 2000w" sizes="(min-width: 1200px) 1200px" width="2000" height="1173" loading="lazy"><figcaption>Aba Network (Rede) nas ferramentas do desenvolvedor</figcaption></figure><p>Vá em frente e limpe sua lista de solicitações pressionando o botão <em>Clear </em>(Limpar), conforme mostrado na imagem abaixo.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/Screenshot-2021-04-25-at-11.42.21-PM.png" class="kg-image" alt="Screenshot-2021-04-25-at-11.42.21-PM" width="131" height="160" loading="lazy"></figure><p>Ao clicar em <em><em><em><em>Load Module A</em></em></em></em>, você verá uma solicitação para <em><em><em><em>modulea-modulea-module.js</em></em></em></em>, como na captura de tela abaixo. Isso verifica se o <em><em><em><em>Módulo A </em></em></em></em>foi carregado de maneira lenta.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/Screenshot-2021-04-25-at-11.46.50-PM.png" class="kg-image" alt="Screenshot-2021-04-25-at-11.46.50-PM" width="419" height="171" loading="lazy"><figcaption>Módulo A carregado</figcaption></figure><p>Do mesmo modo, quando você clica em <em><em><em>Load Module B</em></em></em>, o arquivo <em><em><em>moduleb-moduleb-module.js</em></em></em> é carregado. Isso verifica se o Módulo B foi carregado de maneira lenta.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/Screenshot-2021-04-25-at-11.47.10-PM.png" class="kg-image" alt="Screenshot-2021-04-25-at-11.47.10-PM" width="452" height="201" loading="lazy"><figcaption>Módulo B carregado</figcaption></figure><p>Agora, quando você tentar clicar nos botões, ele não carregará esses arquivos <em><em>js</em></em> novamente.</p><h2 id="casos-de-uso-para-os-ngmodules"><strong>Casos de uso para os NgModules</strong></h2><p>Como vimos, é muito fácil criar módulos de <em>lazy loading</em>. Há muitos casos de uso em que eles são úteis, como:</p><ul><li>Criação de um módulo separado para telas de pré-login e pós-login.</li><li>Em um site <em>e-commerce</em>, as telas voltadas para o fornecedor e as telas voltadas para o cliente podem pertencer a módulos separados. Você também pode criar um módulo separado para pagamento.</li><li>Geralmente, é criado um <em>CommonModule</em> separado, que contém componentes, instruções ou <em>pipelines </em>compartilhados. Instruções como o botão <em><em>Copy Code</em></em> e componentes como <em><em>upvote/downvote</em></em> geralmente são incluídos em um módulo comum.</li></ul><h2 id="conclus-o"><strong>Conclusão</strong></h2><p>Para sites menores, talvez não seja muito importante que todos os módulos sejam carregados de uma só vez. Porém, à medida que o site cresce, é útil ter módulos separados, que são carregados conforme necessário.</p><p>Devido ao <em>lazy loading</em>, o tempo de carregamento dos sites pode ser reduzido drasticamente. Isso é especialmente útil quando se está tentando obter uma classificação mais elevada para SEO. Mesmo que não seja o caso, tempos de carregamento mais curtos significam uma melhor experiência do usuário.</p><p>Você tem interesse em mais tutoriais? Dê uma olhada nestes recursos (em inglês):</p><ul><li><a href="https://arjavdave.com/2021/04/14/learn-test-driven-development-with-integration-tests-in-net-5-0/">Learn TDD with Integration Tests in .NET</a></li><li><a href="https://arjavdave.com/2021/03/31/net-5-setup-authentication-and-authorisation/">How to authenticate &amp; authorise API’s correctly in .NET</a></li><li><a href="https://arjavdave.com/2021/03/22/azure-functions-wkhtmltopdf/">Azure Functions &amp; wkhtmltopdf: Convert HTML to PDF</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como criar uma aplicação do Angular 8 do zero em 11 passos fáceis ]]>
                </title>
                <description>
                    <![CDATA[ O Angular é um dos três frameworks mais populares para o desenvolvimento para  front-end, juntamente com o React e o Vue.js. A versão mais recente* é o Angular 8, lançado em maio de 2019. > Nota de tradução: no momento da criação do texto, a versão mais recente era ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-criar-uma-aplicacao-do-angular-8-do-zero-em-11-passos-faceis/</link>
                <guid isPermaLink="false">63bc5ebead276e05ed757614</guid>
                
                    <category>
                        <![CDATA[ Angular ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Tue, 10 Jan 2023 10:17:27 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/01/desktop-cropped-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/angular-8-tutorial-in-easy-steps/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to build an Angular 8 app from scratch in 11 easy steps</a>
      </p><p>O Angular é um dos três <em>frameworks </em>mais populares para o desenvolvimento para <em>front-end</em>, juntamente com o React e o Vue.js. A versão mais recente* é o Angular 8, lançado em maio de 2019.</p><blockquote><strong>Nota de tradução:</strong> no momento da criação do texto, a versão mais recente era a versão 8. No momento da tradução do artigo, a versão estável mais recente é a versão 12.1.4</blockquote><p>Há muitos novos recursos e melhorias, tanto para a interface de linha de comando, quanto para o próprio <em>framework</em>. Isso resulta em um desempenho melhor e em pacotes de produção menores. Um recurso interessante é o comando <code>ng deploy</code>, que permite que os desenvolvedores criem e façam rapidamente o <em>deploy </em>de suas aplicações do Angular em provedores de hospedagem populares como o Firebase ou o GitHub.</p><p>Neste tutorial, faremos o passo a passo da criação de um exemplo de aplicação do Angular do zero usando várias APIs do Angular, como HttpClient e Material Design.</p><p>Aqui estão algumas das coisas que aprenderemos:</p><ul><li>Como fazer o <em>mock</em> de um servidor de API REST que usa dados falsos a partir de um arquivo JSON</li><li>Como consumir a API REST de nossa aplicação do Angular 8 usando <code>HttpClient</code></li><li>Como lidar com erros do HTTP usando os operadores <code>throwError()</code> e <code>catchError()</code> do RxJS</li><li>Como tentar novamente solicitações de HTTP que falham em condições ruins de rede e como cancelar solicitações pendentes usando os operadores <code>retry()</code> e <code>takeUntil()</code> do RxJS</li><li>Como criar e utilizar os componentes e serviços do Angular</li><li>Como configurar o roteamento e o Angular Material em nosso projeto e criar uma UI de aparência profissional com os componentes do Material Design </li><li>Por fim, aprenderemos a fazer o <em>deploy</em> da aplicação no Firebase usando o comando <code>ng deploy</code>, disponível a partir do Angular 8.3.</li></ul><p>Você também aprenderá por meio de exemplos:</p><ul><li>Como fazer rapidamente o <em>mock </em>de uma API REST com recursos do mundo real (como paginação, por exemplo), que você poderá consumir em sua aplicação antes de passar para o back-end da vida real quando estiver pronto.</li><li>Como configurar a CLI do Angular</li><li>Como inicializar seu projeto do Angular 8</li><li>Como configurar o Angular Material</li><li>Como adicionar componentes e roteamento no Angular</li><li>Como gerar e usar serviços do Angular</li><li>Como consumir APIs REST com o <code>HttpClient</code> do Angular</li><li>Como criar e fazer o <em>deploy </em>de sua aplicação do Angular no Firebase.</li></ul><p>Este tutorial é dividido nos seguintes passos:</p><ul><li>Passo 1 — Instalação da CLI do Angular 8</li><li>Passo 2 — Criação do projeto do Angular 8</li><li>Passo 3 — Inclusão do HttpClient do Angular</li><li>Passo 4 — Criação de componentes</li><li>Passo 5 — Inclusão de roteamento</li><li>Passo 6 — Criação da UI com o Material Components do Angular</li><li>Passo 7 — Criação do <em>mock </em>de uma API REST</li><li>Passo 8 — Consumo da API REST com o HttpClient do Angular</li><li>Passo 9 — Tratamento de erros do HTTP</li><li>Passo 10 — Inclusão de paginação</li><li>Passo 11 — Criação e <em>deploy </em>da aplicação do Angular com o Firebase</li></ul><p>Vamos agora começar com os pré-requisitos!</p><blockquote><strong>Observação</strong>: você pode baixar nosso livro sobre o <strong><strong><a href="https://www.techiediaries.com/angular-book-build-your-first-web-apps/">Angular 8: Build your first web apps with Angular 8 </a></strong></strong>gratuitamente.</blockquote><h1 id="pr-requisitos"><strong>Pré-requisitos</strong></h1><p>Se quiser acompanhar este tutorial, é necessário ter:</p><ul><li>Conhecimento prévio de TypeScript.</li><li>Uma máquina para desenvolvimento com o <strong><strong>Node 8.9</strong> </strong>ou superior e com o <strong><strong>NPM 5.5.1</strong> </strong>ou superior instalados. O Node é necessário em função da CLI do Angular. Você pode visitar o <a href="https://nodejs.org/downloads">site da web oficial</a> e pegar os arquivos binários para seu sistema. Você também pode usar o <a href="https://github.com/nvm-sh/nvm">NVM</a> — Node Version Manager — um script de bash em conformidade com a <a href="https://pt.wikipedia.org/wiki/POSIX">POSIX</a>, para instalar e gerenciar diversas versões do Node.js em sua máquina.</li></ul><p>Se estiver pronto, vamos aprender por meio de exemplos a criar uma aplicação do Angular 8 que consome uma API REST usando o <code>HttpClient</code>. Implementaremos recursos do mundo real, como tratamento de erros e novas tentativas quando solicitações de HTTP não dão certo.</p><h1 id="passo-1-instala-o-da-cli-do-angular-8"><strong>Passo 1 — Instalação da CLI do Angular 8</strong></h1><p>Comecemos com o primeiro passo: onde instalaremos a versão mais recente da CLI do Angular.</p><p>A <a href="https://cli.angular.io/">CLI do Angular</a> é a ferramenta oficial para inicializar e começar a trabalhar com os projetos do Angular. Inicie um terminal (no Mac ou no Linux) e execute o seguinte comando:</p><pre><code class="language-bash">$ npm install -g @angular/cli
</code></pre><p>Ao escrever este tutorial, a <strong><strong>angular/cli v8.3.2</strong></strong> é a que foi instalada em nosso sistema.</p><p>Pronto! Você já pode passar para o próximo passo!</p><h1 id="passo-2-cria-o-de-seu-projeto-do-angular-8"><strong>Passo 2 — Criação de seu projeto do Angular 8</strong></h1><p>Neste passo, usaremos a CLI do Angular para inicializar nosso projeto do Angular.</p><p>Use o terminal para executar os seguintes comandos:</p><pre><code class="language-bash">$ cd ~
$ ng new angular-example</code></pre><p>A CLI perguntará a você <strong>se você quer adicionar o roteamento para o<strong> Angular.</strong></strong> Confirme que sim. Em seguida, ela perguntará <strong>qual formato de folha de estilo você vai querer usar<strong>.</strong></strong> Selecione <strong><strong>CSS</strong></strong>.</p><p>A CLI do Angular vai gerar os arquivos e pastas necessários, instalará os pacotes a partir do npm e configurará automaticamente o roteamento em nosso projeto.</p><p>Vá para a pasta raiz do projeto e execute o servidor de desenvolvimento local usando estes comandos:</p><pre><code class="language-bash">$ cd angular-example
$ ng serve</code></pre><p>Sua aplicação da web do Angular estará disponível a partir do endereço <code>http://localhost:4200/</code>.</p><p>Abra um navegador da web e acesse o endereço <code>http://localhost:4200/</code>. Você deverá ver uma linda página (Iniciando com o Angular 8.3+):</p><p>Você precisará sair do servidor de desenvolvimento em execução e abrir um novo terminal para os próximos passos.</p><p>Você está pronto para o terceiro passo!</p><h1 id="passo-3-inclus-o-do-httpclient-do-angular"><strong>Passo 3 — Inclusão do HttpClient do Angular</strong></h1><p>Neste passo, adicionaremos o <code>HttpClient</code> ao nosso projeto de exemplo.</p><p>Abra o arquivo <code>src/app/app.module.ts</code> e faça as seguintes alterações:</p><pre><code class="language-ts">import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }</code></pre><p>Simplesmente, importamos o <a href="https://angular.io/api/common/http/HttpClientModule#description">HttpClientModule</a> e o incluímos no array de <code>imports</code>.</p><p>É isso – agora, podemos usar o serviço do <code>HttpClient</code> em nosso projeto do Angular para consumir nossa API REST.</p><p>Você está pronto para o quarto passo!</p><h1 id="passo-4-cria-o-dos-componentes-da-ui"><strong>Passo 4 — Criação dos componentes da UI</strong></h1><p>As aplicações do Angular são feitas de componentes. Neste passo, aprenderemos a criar alguns componentes do Angular que fazem composição com nossa UI.</p><p>Abra um novo terminal e execute o seguinte comando:</p><pre><code class="language-bash">$ cd ~/angular-example  
$ ng g component home
</code></pre><p>Você obterá o seguinte resultado no terminal:</p><pre><code>CREATE src/app/home/home.component.html (19 bytes)  
CREATE src/app/home/home.component.spec.ts (614 bytes)  
CREATE src/app/home/home.component.ts (261 bytes)  
CREATE src/app/home/home.component.css (0 bytes)  
UPDATE src/app/app.module.ts (467 bytes)
</code></pre><p>Temos quatro arquivos, todos solicitados pelo nosso componente.</p><p>Em seguida, geraremos o componente About:</p><pre><code class="language-bash">$ ng g component about
</code></pre><p>Depois, abrimos o arquivo <code>src/app/about/about.component.html</code> e adicionamos o seguinte código:</p><pre><code class="language-html">&lt;p style="padding: 15px;"&gt; Esta é a página de "about", que descreve sua aplicação&lt;/p&gt;
</code></pre><p>Você está pronto para o próximo passo!</p><h1 id="passo-5-inclus-o-do-roteamento"><strong>Passo 5 — Inclusão do roteamento</strong></h1><p>Neste passo, aprenderemos a adicionar o roteamento em nosso exemplo.</p><p>Vá para o arquivo <code>src/app/app-routing.module.ts</code> e adicione as seguintes rotas:</p><pre><code class="language-ts">import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';


const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full'},
  { path: 'home', component: HomeComponent },
  { path: 'about', component: AboutComponent },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
</code></pre><p>Importamos os componentes do Angular e declaramos três rotas.</p><p>A primeira rota é para o redirecionamento do caminho vazio para o componente home (a página inicial). Assim, seremos automaticamente redirecionados para a página inicial quando visitamos a aplicação pela primeira vez.</p><p>É isso. Agora que adicionamos o roteamento, podemos passar para o próximo passo!</p><h1 id="passo-6-inclus-o-do-angular-material"><strong>Passo 6 — Inclusão do Angular Material</strong></h1><p>Neste passo do tutorial, aprenderemos a configurar o <a href="https://material.angular.io/">Angular Material</a> em nosso projeto e a criar a UI da nossa aplicação usando seus componentes.</p><p>Vá para o terminal e execute este comando a partir da raiz do projeto:</p><pre><code class="language-bash">$ ng add @angular/material
</code></pre><p>Será solicitado que você escolha o tema. Vamos escolher <strong><strong>Indigo/Pink</strong></strong>.</p><p>Para as outras perguntas – se você deseja <strong>configurar o <strong>HammerJS </strong>para o reconhecimento de gestos</strong> e se você quer <strong>configurar as animações do navegador para o <strong>Angular Material</strong></strong> - pressione <strong><strong>Enter</strong></strong> para usar as respostas padrão.</p><p>Abra o arquivo <code>src/app/app.module.ts</code> e adicione as seguintes importações:</p><pre><code class="language-ts">import { MatToolbarModule,
  MatIconModule,
  MatCardModule,
  MatButtonModule,
  MatProgressSpinnerModule } from '@angular/material';
</code></pre><p>Importamos os módulos destes componentes do Material Design:</p><ul><li><a href="https://material.angular.io/components/toolbar/overview">MatToolbar</a>, que fornece um contêiner para cabeçalhos, títulos ou ações</li><li><a href="https://material.angular.io/components/card/overview">MatCard</a>, que fornece um contêiner de conteúdo para textos, fotos e ações no contexto de um único sujeito.</li><li><a href="https://material.angular.io/components/button/overview">MatButton</a>, que fornece um elemento <code>&lt;button&gt;</code> ou <code>&lt;a&gt;</code> nativo, melhorado com o estilo e efeitos de tinta do Material Design.</li><li><a href="https://material.angular.io/components/progress-spinner/overview">MatProgressSpinner</a>, que fornece um indicador circular de andamento e atividade.</li></ul><p>Em seguida, adicionamos esses módulos ao array de <code>imports</code>:</p><pre><code class="language-ts">@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    AboutComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    BrowserAnimationsModule,
    MatToolbarModule,
    MatIconModule,
    MatButtonModule,
    MatCardModule,
    MatProgressSpinnerModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
</code></pre><p>Depois, abra o arquivo <code>src/app/app.component.html</code> e atualize-o assim:</p><pre><code class="language-html">&lt;mat-toolbar color="primary"&gt;  
&lt;h1&gt;  
My Angular Store  
&lt;/h1&gt;  
&lt;button mat-button routerLink="/"&gt;Home&lt;/button&gt;  
&lt;button mat-button routerLink="/about"&gt;About&lt;/button&gt;&lt;/mat-toolbar&gt;&lt;router-outlet&gt;&lt;/router-outlet&gt;
</code></pre><p>Adicionamos a barra de navegação na parte superior, com dois botões que nos levam para a página inicial e para a página do <em>about</em>, respectivamente.</p><h1 id="passo-7-cria-o-do-mock-da-api-rest"><strong>Passo 7 — Criação do mock da API REST</strong></h1><p>Acesse uma nova interface de linha de comando (a CLI) e comece instalando <code>json-server</code> a partir do npm em seu projeto:</p><pre><code class="language-bash">$ cd ~/angular-example
$ npm install --save json-server 

</code></pre><p>Em seguida, crie uma pasta <code>server</code> na pasta raiz do seu projeto do Angular:</p><pre><code class="language-bash">$ mkdir server
$ cd server

</code></pre><p>Na pasta <code>server</code>, crie um arquivo <code>database.json</code> e adicione o seguinte objeto de JSON:</p><pre><code class="language-json">{
    "products": []
}

</code></pre><p>Esse arquivo JSON funcionará como um banco de dados para seu servidor da API REST. Você precisa apenas adicionar alguns dados a serem servidos pela sua API REST ou usar o <a href="https://github.com/marak/Faker.js/">Faker.js</a> para gerar automaticamente grandes quantidades de dados falsos, porém realistas.</p><p>Volte para sua linha de comando, retorne à pasta <code>server</code> e instale o <code>Faker.js</code> a partir do npm usando o seguinte comando:</p><pre><code class="language-bash">$ cd ..
$ npm install faker --save

</code></pre><p>No momento da criação desse exemplo*, será instalada a versão <strong><strong>4.1.0</strong></strong> do faker.</p><blockquote><strong>Nota de tradução:</strong> no momento da tradução deste texto, o faker está em sua versão <strong>6.6.6</strong>.</blockquote><p>Agora, crie um arquivo <code>generate.js</code> e adicione o código abaixo:</p><pre><code class="language-js">var faker = require('faker');

var database = { products: []};

for (var i = 1; i&lt;= 300; i++) {
  database.products.push({
    id: i,
    name: faker.commerce.productName(),
    description: faker.lorem.sentences(),
    price: faker.commerce.price(),
    imageUrl: "https://source.unsplash.com/1600x900/?product",
    quantity: faker.random.number()
  });
}

console.log(JSON.stringify(database));

</code></pre><p>Primeiro, importamos o faker. Em seguida, definimos um objeto com um array vazio para os produtos (<em>products</em>). Depois, inserimos um laço <em><em>for</em></em> para criar <em><em>300</em></em> entradas falsas usando os métodos do faker, como <code>faker.commerce.productName()</code>, para gerar os nomes dos produtos. <a href="https://www.npmjs.com/package/faker/v/5.5.3">Confira todos os métodos disponíveis</a>. Por fim, convertemos o objeto do banco de dados em uma string e a registramos na saída padrão.</p><p>Então, adicionamos os scripts <code>generate</code> e <code>server</code> ao arquivo <code>package.json</code>:</p><pre><code class="language-json">  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "generate": "node ./server/generate.js &gt; ./server/database.json",
    "server": "json-server --watch ./server/database.json"
  },

</code></pre><p>Retornamos depois disso à interface de linha de comando e executamos o script <code>generate</code> usando o seguinte comando:</p><pre><code class="language-bash">$ npm run generate

</code></pre><p>Por fim, executamos o servidor da API REST usando este comando:</p><pre><code class="language-bash">$ npm run server

</code></pre><p>Agora, você pode enviar solicitações de HTTP ao servidor como faz com qualquer servidor de API REST típico. Ele estará disponível no endereço <code>http://localhost:3000/</code>.</p><p>Estes são os endpoints da API que poderemos usar com o nosso servidor de API REST em JSON:</p><ul><li><code>GET /products</code> para obter os produtos</li><li><code>GET /products/&lt;id&gt;</code> para obter um único produto por id</li><li><code>POST /products</code> para criar um produto</li><li><code>PUT /products/&lt;id&gt;</code> para atualizar um produto por id</li><li><code>PATCH /products/&lt;id&gt;</code> para atualizar parcialmente um produto por id</li><li><code>DELETE /products/&lt;id&gt;</code> para excluir um produto por id</li></ul><p>Você pode usar os parâmetros <code>_page</code> e <code>_limit</code> para obter os dados de modo paginado. No cabeçalho <code>Link</code>, você terá os links <code>first</code>, <code>prev</code>, <code>next</code> e <code>last</code>.</p><p>Deixe o servidor de API REST em JSON em execução e abra uma nova interface de linha de comando para digitar os comandos para os próximos passos.</p><h1 id="passo-8-cria-o-de-um-servi-o-para-o-consumo-da-api-rest-com-o-httpclient-do-angular"><strong>Passo 8 — Criação de um serviço para o consumo da API REST com o HttpClient do Angular</strong></h1><p>Neste passo, aprenderemos a consumir nossa API REST a partir do Angular usando <code>HttpClient</code>.</p><p>Precisamos criar um serviço do Angular para o encapsulamento do código que nos permitirá consumir os dados de nosso servidor API REST.</p><p>Vá para o terminal e execute o seguinte comando:</p><pre><code class="language-bash">$ ng g service api
</code></pre><p>Depois, vá para o arquivo <code>src/app/api.service.ts</code>, importe e injete o <code>HttpClient</code>:</p><pre><code class="language-ts">import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

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

  private SERVER_URL = "http://localhost:3000";

  constructor(private httpClient: HttpClient) { }
}
</code></pre><p>Importamos e injetamos o serviço <code>HttpClient</code> e definimos a variável <code>SERVER_URL</code>, que contém o endereço de nosso servidor de API REST.</p><p>Depois, definimos um método <code>get()</code>, que envia uma solicitação GET para o <em>endpoint </em>da API REST:</p><pre><code class="language-ts">import { Injectable } from '@angular/core';  
import { HttpClient } from '@angular/common/http';

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

	private SERVER_URL = "http://localhost:3000";
	constructor(private httpClient: HttpClient) { }

	public get(){  
		return this.httpClient.get(this.SERVER_URL);  
	}  
}
</code></pre><p>O método simplesmente invoca o método <code>get()</code> do <code>HttpClient</code> para enviar solicitações GET ao servidor de API REST.</p><p>Depois disso, precisamos usar o serviço em nosso componente <em>home</em> (a página inicial). Abra o arquivo <code>src/app/home/home.component.ts</code>, importe e injete o serviço de dados, assim:</p><pre><code class="language-ts">import { Component, OnInit } from '@angular/core';  
import { ApiService } from '../api.service';

@Component({  
	selector: 'app-home',  
	templateUrl: './home.component.html',  
	styleUrls: ['./home.component.css']  
})  
export class HomeComponent implements OnInit {
	products = [];
	constructor(private apiService: ApiService) { }
	ngOnInit() {
		this.apiService.get().subscribe((data: any[])=&gt;{  
			console.log(data);  
			this.products = data;  
		})  
	}
}
</code></pre><p>Importamos e injetamos <code>ApiService</code>. Agora, definimos uma variável <code>products</code> e chamamos o método <code>get()</code> do serviço para buscar os dados do servidor da API REST em JSON.</p><p>A seguir, abrimos o arquivo <code>src/app/home/home.component.html</code> e o atualizamos do seguinte modo:</p><pre><code class="language-html">&lt;div style="padding: 13px;"&gt;
    &lt;mat-spinner *ngIf="products.length === 0"&gt;&lt;/mat-spinner&gt;

    &lt;mat-card *ngFor="let product of products" style="margin-top:10px;"&gt;
        &lt;mat-card-header&gt;
            &lt;mat-card-title&gt;{{product.name}}&lt;/mat-card-title&gt;
            &lt;mat-card-subtitle&gt;{{product.price}} $/ {{product.quantity}}
            &lt;/mat-card-subtitle&gt;
        &lt;/mat-card-header&gt;
        &lt;mat-card-content&gt;
            &lt;p&gt;
                {{product.description}}
            &lt;/p&gt;
            &lt;img style="height:100%; width: 100%;" src="{{ product.imageUrl }}" /&gt;
        &lt;/mat-card-content&gt;
        &lt;mat-card-actions&gt;
      &lt;button mat-button&gt; Buy product&lt;/button&gt;
    &lt;/mat-card-actions&gt;
    &lt;/mat-card&gt;
&lt;/div&gt;
</code></pre><p>Usamos o componente <code>&lt;mat-spinner&gt;</code> para exibir um <em>spinner </em>de carregamento quando o tamanho do array <code>products</code> for igual a zero, ou seja, antes de qualquer dado ter sido recebido do servidor da API REST.</p><p>Depois, percorremos o array <code>products</code> e usamos o card do Material para exibir <code>name</code>, <code>price</code>, <code>quantity</code>, <code>description</code> e <code>image</code> de cada produto.</p><p>Esta é uma imagem da página inicial após a busca dos dados em JSON:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/01/0_R7qs5jGg_IlOtTWF.png" class="kg-image" alt="0_R7qs5jGg_IlOtTWF" width="301" height="524" loading="lazy"></figure><p>Em seguida, veremos como adicionar o tratamento de erros ao nosso serviço.</p><h1 id="passo-9-inclus-o-de-tratamento-de-erros"><strong>Passo 9 — Inclusão de tratamento de erros</strong></h1><p>Neste passo, aprenderemos a adicionar o tratamento de erros em nosso exemplo.</p><p>Vá para o arquivo <code>src/app/api.service.ts</code> e atualize-o assim:</p><pre><code class="language-ts">import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from "@angular/common/http";

import {  throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';


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

  private SERVER_URL = "http://localhost:3000/products";

  constructor(private httpClient: HttpClient) { }

  handleError(error: HttpErrorResponse) {
    let errorMessage = 'Unknown error!';
    if (error.error instanceof ErrorEvent) {
      // Client-side errors
      errorMessage = `Error: ${error.error.message}`;
    } else {
      // Server-side errors
      errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
    }
    window.alert(errorMessage);
    return throwError(errorMessage);
  }

  public sendGetRequest(){
    return this.httpClient.get(this.SERVER_URL).pipe(catchError(this.handleError));
  }
}</code></pre><p>Esta é uma imagem com um exemplo de erro no console do navegador:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/01/0_gZUHzXPjrRSSK4ZF.png" class="kg-image" alt="0_gZUHzXPjrRSSK4ZF" width="442" height="277" loading="lazy"></figure><p>No próximo passo, veremos como adicionar a paginação em nossa aplicação</p><h1 id="passo-10-inclus-o-da-pagina-o"><strong>Passo 10 — Inclusão da paginação</strong></h1><p>Neste passo, aprenderemos a adicionar o suporte à paginação de dados usando o cabeçalho <code>Link</code> da resposta do HTTP recebida do servidor da API REST.</p><p>Por padrão, o <code>HttpClient</code> fornece apenas o corpo da resposta. Porém, em nossa aplicação, necessitamos fazer o <em>parsing</em> do cabeçalho <code>Link</code> para a extração dos links de paginação. Desse modo, precisamos instruir o <code>HttpClient</code> a nos dar a resposta de <a href="https://angular.io/api/common/http/HttpResponse">HttpResponse</a> completa usando a opção <code>observe</code>.</p><p>O cabeçalho <code>Link</code> no HTTP permite que o servidor oriente um <em>client </em>interessado para outros recursos que contenham metadados sobre o recurso solicitado. Veja mais sobre o cabeçalho na <a href="https://www.w3.org/wiki/LinkHeader">página da W3C</a> (em inglês).</p><p>Abra o arquivo <code>src/app/data.service.ts</code> e importe o operador <code>tap()</code> do RxJS:</p><pre><code class="language-ts">import { retry, catchError, tap } from 'rxjs/operators';
</code></pre><p>Depois, adicionamos estas variáveis:</p><pre><code class="language-ts">public first: string = "";  
public prev: string = "";  
public next: string = "";  
public last: string = "";
</code></pre><p>Em seguida, adicionamos o método <code>parseLinkHeader()</code>, que será usado para fazer o <em>parsing </em>do cabeçalho <code>Link</code> e para preencher as variáveis anteriores:</p><pre><code class="language-ts">  parseLinkHeader(header) {
    if (header.length == 0) {
      return ;
    }

    let parts = header.split(',');
    var links = {};
    parts.forEach( p =&gt; {
      let section = p.split(';');
      var url = section[0].replace(/&lt;(.*)&gt;/, '$1').trim();
      var name = section[1].replace(/rel="(.*)"/, '$1').trim();
      links[name] = url;

    });

    this.first  = links["first"];
    this.last   = links["last"];
    this.prev   = links["prev"];
    this.next   = links["next"]; 
  }
</code></pre><p>Então, atualizamos <code>sendGetRequest()</code> da seguinte maneira:</p><pre><code class="language-ts">  public sendGetRequest(){
    // Adicione parâmetros _page e _limit seguros, codificados como URL 

    return this.httpClient.get(this.SERVER_URL, {  params: new HttpParams({fromString: "_page=1&amp;_limit=20"}), observe: "response"}).pipe(retry(3), catchError(this.handleError), tap(res =&gt; {
      console.log(res.headers.get('Link'));
      this.parseLinkHeader(res.headers.get('Link'));
    }));
  }</code></pre><p>Adicionamos a opção <code>observe</code> com o valor <code>response</code> no parâmetro <code>options</code> do método <code>get()</code> para termos a resposta completa do HTTP com os cabeçalhos. A seguir, usamos o operador <code>tap()</code> do RxJS para fazer o <em>parsing </em>do cabeçalho <code>Link</code> antes de retornar o <em>Observable</em> final.</p><p>Como <code>sendGetRequest()</code> agora retorna um <em>Observable </em>com uma resposta completa de HTTP, precisamos atualizar o componente <em>home.</em> Portanto, abra o arquivo <code>src/app/home/home.component.ts</code> e importe <code>HttpResponse</code> assim:</p><pre><code class="language-ts">import { HttpResponse } from '@angular/common/http';
</code></pre><p>Depois, atualize o método <code>subscribe()</code> da seguinte maneira:</p><pre><code class="language-ts">ngOnInit(){

this.apiService.sendGetRequest().pipe(takeUntil(this.destroy$)).subscribe((res: HttpResponse&lt;any&gt;)=&gt;{  
	console.log(res);  
	this.products = res.body;  
})  
}
</code></pre><p>Podemos agora acessar os dados do objeto <code>body</code> da resposta recebida de HTTP.</p><p>Em seguida, retornamos ao arquivo <code>src/app/data.service.ts</code> e adicionamos o seguinte método:</p><pre><code class="language-ts">public sendGetRequestToUrl(url: string){  
	return this.httpClient.get(url, { observe: "response"}).pipe(retry(3), 			
	catchError(this.handleError), tap(res =&gt; {  
		console.log(res.headers.get('Link'));  
		this.parseLinkHeader(res.headers.get('Link'));
	}));  
}
</code></pre><p>Esse método é semelhante ao método <code>sendGetRequest()</code>, com a exceção de que recebe o URL para o qual precisamos enviar uma solicitação GET de HTTP.</p><p>Retorne ao arquivo <code>src/app/home/home.component.ts</code> e adicione os métodos a seguir:</p><pre><code class="language-ts"> public firstPage() {
    this.products = [];
    this.apiService.sendGetRequestToUrl(this.apiService.first).pipe(takeUntil(this.destroy$)).subscribe((res: HttpResponse&lt;any&gt;) =&gt; {
      console.log(res);
      this.products = res.body;
    })
  }
  public previousPage() {

    if (this.apiService.prev !== undefined &amp;&amp; this.apiService.prev !== '') {
      this.products = [];
      this.apiService.sendGetRequestToUrl(this.apiService.prev).pipe(takeUntil(this.destroy$)).subscribe((res: HttpResponse&lt;any&gt;) =&gt; {
        console.log(res);
        this.products = res.body;
      })
    }

  }
  public nextPage() {
    if (this.apiService.next !== undefined &amp;&amp; this.apiService.next !== '') {
      this.products = [];
      this.apiService.sendGetRequestToUrl(this.apiService.next).pipe(takeUntil(this.destroy$)).subscribe((res: HttpResponse&lt;any&gt;) =&gt; {
        console.log(res);
        this.products = res.body;
      })
    }
  }
  public lastPage() {
    this.products = [];
    this.apiService.sendGetRequestToUrl(this.apiService.last).pipe(takeUntil(this.destroy$)).subscribe((res: HttpResponse&lt;any&gt;) =&gt; {
      console.log(res);
      this.products = res.body;
    })
  }</code></pre><p>Por fim, abra o arquivo <code>src/app/home/home.component.html</code> e atualize o <em>template </em>da seguinte maneira:</p><pre><code class="language-html">&lt;div style="padding: 13px;"&gt;
    &lt;mat-spinner *ngIf="products.length === 0"&gt;&lt;/mat-spinner&gt;

    &lt;mat-card *ngFor="let product of products" style="margin-top:10px;"&gt;
        &lt;mat-card-header&gt;
            &lt;mat-card-title&gt;#{{product.id}} {{product.name}}&lt;/mat-card-title&gt;
            &lt;mat-card-subtitle&gt;{{product.price}} $/ {{product.quantity}}
            &lt;/mat-card-subtitle&gt;
        &lt;/mat-card-header&gt;
        &lt;mat-card-content&gt;
            &lt;p&gt;
                {{product.description}}
            &lt;/p&gt;
            &lt;img style="height:100%; width: 100%;" src="{{ product.imageUrl }}" /&gt;
        &lt;/mat-card-content&gt;
        &lt;mat-card-actions&gt;
      &lt;button mat-button&gt; Buy product&lt;/button&gt;
    &lt;/mat-card-actions&gt;
    &lt;/mat-card&gt;

&lt;/div&gt;
&lt;div&gt;
    &lt;button (click) ="firstPage()" mat-button&gt; First&lt;/button&gt;
    &lt;button (click) ="previousPage()" mat-button&gt; Previous&lt;/button&gt;
    &lt;button (click) ="nextPage()" mat-button&gt; Next&lt;/button&gt;
    &lt;button (click) ="lastPage()" mat-button&gt; Last&lt;/button&gt;
&lt;/div&gt;</code></pre><p>Está é uma imagem da nossa aplicação:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/01/0_c_21mFswM-ZiReUi.png" class="kg-image" alt="0_c_21mFswM-ZiReUi" width="297" height="521" loading="lazy"></figure><h1 id="passo-11-cria-o-e-deploy-da-aplica-o-do-angular-com-o-firebase"><strong>Passo 11 — Criação e <em>deploy </em>da aplicação do Angular com o Firebase</strong></h1><p>Retorne à interface de linha de comando. Certifique-se de estar na pasta raiz do seu projeto do Angular e execute o seguinte comando:</p><pre><code class="language-bash">$ ng add @angular/fire

</code></pre><p>Isso adicionará a capacidade de <em>deploy </em>no Firebase ao seu projeto.</p><p>No momento de criação deste tutorial, será instalada a versão <strong>5.2.1</strong> do <strong><strong>@angular/fire</strong></strong>.</p><blockquote><strong>Nota de tradução:</strong> no momento da tradução deste texto, o <strong>@angular/fire</strong> está em sua versão <strong>7.4.0</strong>.</blockquote><p>O comando também atualizará o <code>package.json</code> do nosso projeto, adicionando a seguinte seção:</p><pre><code class="language-json">        "deploy": {
          "builder": "@angular/fire:deploy",
          "options": {}
        }

</code></pre><p>A CLI solicitará que você <strong>cole o código de autorização</strong>, abrirá seu navegador padrão e pedirá que você dê à CLI do Firebase permissões para administrar sua conta no Firebase.</p><p>Depois de entrar com a conta do Google associada à conta do Firebase, você receberá o código de autorização.</p><p>Em seguida, será solicitado a você que <strong>selecione um projeto<strong> </strong>usando as teclas de seta ou digitando para pesquisar</strong>. Você precisa ter criado um projeto do Firebase antes disso.</p><p>A CLI criará os arquivos <code>firebase.json</code> e <code>.firebaserc</code>, atualizando o arquivo <code>angular.json</code> conforme necessário.</p><p>Depois, faça o <em>deploy </em>de sua aplicação no Firebase usando o seguinte comando:</p><pre><code class="language-bash">$ ng deploy

</code></pre><p>O comando produzirá uma <em>build </em>otimizada de sua aplicação (equivalente ao uso do comando <code>ng deploy --prod</code>). Ele, então, fará o <em>upload </em>dos ativos de produção para a hospedagem do Firebase.</p><h1 id="conclus-o"><strong>Conclusão</strong></h1><p>Neste tutorial passo a passo, você aprendeu a criar uma aplicação do Angular do zero usando a versão 8.3 do Angular ou superior.</p><p>Você também aprendeu a fazer o <em>mock </em>de um <em>back-end</em> de API REST para sua aplicação do Angular sem, praticamente, escrever linha alguma de código.</p><p>Vimos também como criar um projeto usando a CLI do Angular, adicionar o <code>HttpClient</code> e o Angular Material para o envio de solicitações de HTTP ao seu <em>mock</em> de <em>back-end </em>de API REST e para a estilização da UI com os componentes do Material Design.</p><p>Por fim, aprendemos como fazer o <em>deploy </em>da aplicação do Angular no Firebase usando o comando <code>ng deploy</code>, disponível a partir da versão 8.3 do Angular.</p><p>Confira outros <a href="https://www.techiediaries.com/angular">tutoriais do </a><a href="https://www.techiediaries.com/angular">Angular</a> (em inglês).</p><p>Você pode entrar em contato com o autor usando estes links:</p><ul><li><a href="https://www.ahmedbouchefra.com/">Site pessoal na web</a></li><li><a href="https://twitter.com/ahmedbouchefra">Twitter</a></li><li><a href="https://www.linkedin.com/in/mr-ahmed/">LinkedIn</a></li><li><a href="https://github.com/techiediaries">Github</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como instalar o Angular no Windows: um guia de Angular CLI, Node.js e ferramentas de criação ]]>
                </title>
                <description>
                    <![CDATA[ Neste tutorial, aprenderemos a instalar a Angular CLI no Windows e a usá-la para criar um projeto em Angular. O que é a Angular CLI? A Angular CLI é a ferramenta oficial para inicializar e trabalhar com projetos em Angular. Ela evita a inconveniência das configurações complexas e das ferramentas ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-instalar-o-angular-no-windows-um-guia-de-angular-cli-node-js-e-ferramentas-de-criacao/</link>
                <guid isPermaLink="false">62653dd86daab205304b30a4</guid>
                
                    <category>
                        <![CDATA[ Angular ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Tue, 26 Apr 2022 12:05:23 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/angular-cli-install.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-install-angular-on-windows-a-guide-to-angular-cli-node-js-and-build-tools/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Install Angular on Windows: A Guide to Angular CLI, Node.js, and Build Tools</a>
      </p><p>Neste tutorial, aprenderemos a instalar a Angular CLI no Windows e a usá-la para criar um projeto em Angular.</p><h2 id="o-que-a-angular-cli"><strong>O que é a Angular CLI?</strong></h2><p>A Angular CLI é a ferramenta oficial para inicializar e trabalhar com projetos em Angular. Ela evita a inconveniência das configurações complexas e das ferramentas de build, como TypeScript, Webpack e assim por diante.</p><p>Depois de instalar a Angular CLI, você precisa executar um comando para gerar um projeto e outro para servi-lo usando um servidor de desenvolvimento local para rodar sua aplicação.</p><p>Como ocorre com a maioria das ferramentas de front-end nos dias de hoje, a Angular CLI foi criada com base no Node.js.</p><p>O Node.js é uma tecnologia de servidor que permite que você execute o JavaScript no servidor e crie aplicações da web no lado do servidor. No entanto, o Angular é uma tecnologia de front-end. Portanto, mesmo que você precise instalar o Node.js em sua máquina de desenvolvimento, é apenas para a execução da CLI.</p><p>Ao fazer o build de sua aplicação para produção, o Node.js já não será mais necessário, pois os <em>bundles</em> (conjuntos) finais são apenas HTML, CSS e JavaScript estáticos que podem ser servidos em qualquer servidor ou CDN.</p><p>Dito isso, se você está criando uma <a href="https://shabang.dev/question/how-to-create-a-new-angular-9-project-using-npm/">aplicação da web com Angular</a> full-stack, poderá precisar do Node.js para a criação do back-end se quiser usar o JavaScript para o front-end e para o back-end.</p><p>Confira a stack MEAN – é uma arquitetura que inclui o MongoDB, o Express (um framework de servidor da web e API REST criado com base no Node.js) e o Angular. Você pode ler este <a href="https://www.techiediaries.com/angular-9-8-mean-stack-authentication-tutorial-and-example-with-node-and-mongodb/">artigo</a> (em inglês) se quiser um tutorial passo a passo para iniciar.</p><p>Neste caso, o Node.js é usado para criar o back-end de sua aplicação e pode ser substituído por qualquer tecnologia do lado do servidor que você deseje, como o PHP, o Ruby ou o Python. O Angular, no entanto, não depende do Node.js, exceto para sua ferramenta de CLI e para a instalação de pacotes com o npm.</p><p>NPM é a sigla para Node Package Manager (gerenciador de pacotes do Node, em português). É um registro para a hospedagem de pacotes do Node. Nos últimos anos, ele também tem sido usado para publicar pacotes de front-end e bibliotecas como o Angular, o React, o Vue.js e até mesmo o Bootstrap.</p><p><strong>Observação</strong>: você pode fazer o download de nosso livro, <strong><a href="https://www.techiediaries.com/angular-book-build-your-first-web-apps/">Hands-on A<strong>ngular</strong>:<strong> </strong>Learn<strong> Angular </strong>Step By Step</a></strong> (em inglês), gratuitamente.</p><h2 id="instala-o-da-angular-cli-no-windows"><strong>Instalação da Angular CLI no Windows</strong></h2><p>Primeiro, você precisa ter o Node e o npm instalados na sua máquina de desenvolvimento. Existem muitas maneiras de se fazer isso, tais como:</p><ul><li>usar o NVM (Node Version Manager) para a instalação e trabalho com muitas versões do Node em seu sistema</li><li>usar o gerenciador de pacotes oficial do seu sistema operacional</li><li>instalar a partir do site oficial da web.</li></ul><p>Vamos simplificar e usar o site oficial. Basta visitar a <a href="https://nodejs.org/en/download/">página de download</a> e pegar os arquivos binários para o Windows e, depois, seguir o assistente de configuração.</p><p>Certifique-se de que o Node esteja instalado em seu sistema executando o comando abaixo em um prompt de comando, que deverá exibir a versão instalada do Node:</p><pre><code class="language-bash">$ node -v
</code></pre><p>Depois, execute o seguinte comando para instalar a Angular CLI:</p><pre><code class="language-bash">$ npm install @angular/cli
</code></pre><p>Depois de o comando terminar a instalação, a Angular CLI já deverá estar instalada em sua máquina.</p><h2 id="um-guia-r-pido-para-a-angular-cli"><strong>Um guia rápido para a Angular CLI</strong></h2><p>Depois de instalar a Angular CLI, você pode executar diversos comandos. Comecemos conferindo a versão instalada da CLI:</p><pre><code class="language-bash">$ ng version
</code></pre><p>Um segundo comando que talvez você queira executar é o comando <code>help</code>, que ajudará a obter uma lista de comandos a serem usados:</p><pre><code class="language-bash">$ ng help
</code></pre><p>A CLI oferece os comandos a seguir:</p><p><code>add</code>: adiciona suporte a uma biblioteca externa em seu projeto.</p><p><code>build (b)</code>: compila uma aplicação do Angular em seu diretório de saída, chamado <code>dist/</code> no caminho de saída fornecido. Este comando deve ser executado dentro de um diretório de espaço de trabalho.</p><p><code>config</code>: obtém ou configura os valores de configuração do Angular.</p><p><code>doc (d)</code>: abre a documentação oficial do Angular (<a href="https://angular.io/">angular.io</a>) em um navegador, buscando uma palavra-chave determinada.</p><p><code>e2e (e)</code>: faz o build e serve uma aplicação do Angular, depois executa testes de ponta a ponta usando o Protractor.</p><p><code>generate (g)</code>: gera e/ou modifica arquivos com base em um esquema.</p><p><code>help</code>: lista os comandos disponíveis e suas descrições breves.</p><p><code>lint (l)</code>: executa as ferramentas de linting no código da aplicação em Angular em uma determinada pasta de projeto.</p><p><code>new (n)</code>: cria um espaço de trabalho e uma aplicação inicial em Angular.</p><p><code>run</code>: executa um destino personalizado definido em seu projeto.</p><p><code>serve (s)</code>: faz o build e serve sua aplicação, fazendo um novo build a cada alteração de arquivos.</p><p><code>test (t)</code>: executa os testes unitários em um projeto.</p><p><code>update</code>: atualiza sua aplicação e suas dependências. Consulte &nbsp;<a href="https://update.angular.io/">https://update.angular.io/</a> (em inglês)</p><p><code>version (v)</code>: mostra a versão da Angular CLI.</p><p><code>xi18n</code>: extrai as mensagens i18n do código-fonte.</p><h2 id="gera-o-de-um-projeto"><strong>Geração de um projeto</strong></h2><p>Você pode usar a Angular CLI para gerar rapidamente seu projeto em Angular executando o seguinte comando em sua interface de linha de comando:</p><pre><code class="language-bash">$ ng new frontend

</code></pre><p><em>Observação<em>:</em></em><strong><strong> </strong>"<strong>frontend</strong>"</strong> <em>é o nome do projeto<em>. </em>Você pode, logicamente, escolher o nome válido que quiser para seu projeto<em>. </em>Como criaremos uma aplicação<em> full-stack</em>, estou usando </em>frontend <em>como o nome para a aplicação de <em>front-end .</em></em></p><p>A CLI perguntará <em><em>Would you like to add Angular routing?</em> ("Quer adicionar o roteamento do Angular?")</em>. Você pode responder com <code>y</code> (Sim) ou <code>n</code> (Não). Não, neste caso, é a opção padrão. Também será perguntado sobre o formato da folha de estilos (<em>stylesheet</em>) que você quer usar (por exemplo, o CSS). Escolha suas opções e pressione <code>Enter</code> &nbsp;para continuar.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/vQaSm5I.jpg" class="kg-image" alt="vQaSm5I" width="316" height="265" loading="lazy"></figure><p>Depois disso, seu projeto estará criado com uma estrutura de diretórios e alguns arquivos com configurações e código. A maioria estará nos formatos TypeScript e JSON. Vejamos a função de cada diretório/arquivo:</p><ul><li><code>/e2e/</code>: contém os testes <em>end-to-end</em> (simulação do comportamento do usuário) do site</li><li><code>/node_modules/</code>: todas as bibliotecas de terceiros são instaladas nesta pasta usando <code>npm install</code></li><li><code>/src/</code>: contém o código-fonte da aplicação. A maior parte do trabalho será feita aqui</li><li><code>/app/</code>: contém módulos e componentes</li><li><code>/assets/</code>: contém os ativos estáticos, como imagens, ícones e estilos</li><li><code>/environments/</code>: contém arquivos de configuração específicos do ambiente (produção e desenvolvimento)</li><li><code>browserslist</code>: necessário para o autoprefixador para suporte ao CSS</li><li><code>favicon.ico</code>: o favicon</li><li><code>index.html</code>: o arquivo HTML principal</li><li><code>karma.conf.js</code>: o arquivo de configuração para o Karma (uma ferramenta de testes)</li><li><code>main.ts</code>: o arquivo inicial principal, a partir de onde o <em><em>AppModule</em></em> é iniciado</li><li><code>polyfills.ts</code>: polyfills necessários ao Angular</li><li><code>styles.css</code>: o arquivo de folha de estilos (<em>stylesheet</em>) global do projeto</li><li><code>test.ts</code>: um arquivo de configuração para o Karma</li><li><code>tsconfig.*.json</code>: os arquivos de configuração para o TypeScript</li><li><code>angular.json</code>: contém as configurações para a CLI</li><li><code>package.json</code>: contém as informações básicas do projeto (nome, descrição e dependências)</li><li><code>README.md</code>: um arquivo em markdown que contém a descrição do projeto</li><li><code>tsconfig.json</code>: o arquivo de configuração para o TypeScript</li><li><code>tslint.json</code>: o arquivo de configuração para o TSlint (uma ferramenta de análise estática)</li></ul><h2 id="como-servir-o-projeto"><strong>Como servir o projeto</strong></h2><p>A Angular CLI fornece um conjunto de ferramentas completo para desenvolver aplicações de front-end em sua máquina local. Assim, não é preciso instalar um servidor para servir o projeto — você pode, simplesmente, usar o comando <code>ng serve</code> a partir do terminal para servir seu projeto localmente.</p><p>Primeiro, navegue dentro de sua pasta do projeto e execute os seguintes comandos:</p><pre><code class="language-bash">$ cd frontend
$ ng serve

</code></pre><p>Agora, você pode navegar até o endereço <a href="http://localhost:4200/">http://localhost:4200/</a> para começar a mexer com sua aplicação de front-end. A página recarregará automaticamente caso você mude qualquer arquivo do código-fonte.</p><h2 id="gera-o-de-artefatos-do-angular"><strong>Geração de artefatos do Angular</strong></h2><p>A Angular CLI fornece um comando <code>ng generate</code> que ajuda os desenvolvedores a gerar artefatos básicos do Angular, como módulos, componentes, diretivas, <em>pipes</em> e serviços:</p><pre><code class="language-bash">$ ng generate component meu-componente
</code></pre><p><code>meu-componente</code> é o nome do componente. A Angular CLI automaticamente adicionará uma referência a <code>components</code>, <code>directives</code> e <code>pipes</code> no arquivo <code>src/app.module.ts</code>.</p><p>Se quiser adicionar seu componente, diretiva ou <em>pipe</em> para outro módulo (que não seja o módulo principal da aplicação, <code>app.module.ts</code>), você pode simplesmente prefixar o nome do componente com o nome do módulo e uma barra assim :</p><pre><code class="language-bash">$ ng g component meu-modulo/meu-componente
</code></pre><p><code>meu-modulo</code> é o nome de um módulo existente.</p><h2 id="conclus-o"><strong>Conclusão</strong></h2><p>Neste tutorial, vimos como instalar a Angular CLI na sua máquina com Windows e como a usamos para inicializar um novo projeto do Angular do zero.</p><p>Também vimos diversos comandos que você pode usar durante o desenvolvimento de seu projeto para gerar artefatos do Angular, como módulos, componentes e serviços.</p><p>Confira nossos outros <a href="https://www.techiediaries.com/angular/">tutoriais de Angular</a> (em inglês).</p><p>Você pode entrar em contato com o autor por meio de seu <a href="https://www.ahmedbouchefra.com/contact">site pessoal na web</a>, bem como segui-lo no <a href="https://twitter.com/ahmedbouchefra">Twitter</a>, no <a href="https://www.linkedin.com/in/mr-ahmed/">LinkedIn</a> e no <a href="https://github.com/techiediaries">Github</a>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como validar formulários reativos no Angular ]]>
                </title>
                <description>
                    <![CDATA[ Introdução Neste artigo, aprenderemos sobre a validação de formulários reativos em Angular. Criaremos um formulário simples de registro de usuário e implementaremos algumas validações integradas nele. Juntamente com as validações integradas, também vamos implementar algumas validações personalizadas para o formulário reativo. Consideraremos as seguintes validações personalizadas para esta demonstração:  ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-validar-formularios-reativos-no-angular/</link>
                <guid isPermaLink="false">6254277a6daab205304b1029</guid>
                
                    <category>
                        <![CDATA[ Angular ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lais Golin ]]>
                </dc:creator>
                <pubDate>Tue, 12 Apr 2022 19:53:45 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/5f9c9e95740569d1a4ca3de6.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-validate-angular-reactive-forms/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Validate Angular Reactive Forms</a>
      </p><h3 id="introdu-o">Introdução</h3><p>Neste artigo, aprenderemos sobre a validação de formulários reativos em Angular. Criaremos um formulário simples de registro de usuário e implementaremos algumas validações integradas nele. Juntamente com as validações integradas, também vamos implementar algumas validações personalizadas para o formulário reativo.</p><p>Consideraremos as seguintes validações personalizadas para esta demonstração:</p><ul><li>Verificar a disponibilidade do nome do usuário</li><li>Validar o padrão de senha</li><li>Validar a senha digitada em dois campos diferentes</li></ul><p>Veja a aplicação em ação:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/reactiveFormValidation.gif" class="kg-image" alt="reactiveFormValidation" width="650" height="648" loading="lazy"></figure><h2 id="pr-requisitos">Pré-requisitos</h2><ul><li>Instalar o Visual Studio Code por este <a href="https://code.visualstudio.com/">link</a></li><li>Instalar a versão mais atualizada da Angular CLI por este <a href="https://cli.angular.io/">link</a> </li></ul><h2 id="c-digo-fonte"><strong>Código-fonte </strong></h2><p>Obtenha o código-fonte pelo <a href="https://github.com/AnkitSharma-007/angular-forms-validation">GitHub</a>.</p><h2 id="criando-a-aplica-o-em-angular"><strong>Criando a aplicação em Angular</strong></h2><p>Navegue até a pasta onde deseja criar seu arquivo de projeto. Abra uma janela de comando e execute o comando mostrado abaixo:</p><pre><code>ng new angular-forms-validation --routing=false --style=scss</code></pre><p>Estamos especificando o comando para criar uma nova aplicação em Angular. A opção de criar o módulo de roteamento é definida como falsa e a extensão de arquivos de estilo é definida como <code>scss</code>. Este comando criará o projeto em Angular com o nome de <code>angular-forms-validation</code>.</p><p>Altere os diretórios, vá para o novo projeto e abra-o no Visual Studio Code usando os comandos mostrados abaixo:</p><pre><code>cd angular-forms-validation 
code .</code></pre><h2 id="instalando-o-bootstrap"><strong>Instalando o Bootstrap</strong></h2><p>Execute o comando abaixo para instalar a biblioteca do Bootstrap na pasta do projeto:</p><pre><code>npm install bootstrap --save</code></pre><p>Adicione a seguinte definição de importação no arquivo <code>styles.scss</code>:</p><pre><code>@import "~bootstrap/dist/css/bootstrap.css";</code></pre><h2 id="criando-o-servi-o-de-valida-o"><strong>Criando o serviço de validação</strong></h2><p>Execute o comando abaixo para criar um novo serviço: </p><pre><code>ng g s services\customvalidation</code></pre><p>Este comando criará uma pasta nomeada serviços com dois arquivos — <code>customvalidation.service.ts</code> e <code>customvalidation.service.spec.ts</code>. Abra o arquivo <code>customvalidation.service.ts</code> e cole o código abaixo:</p><pre><code class="language-js">import { Injectable } from '@angular/core';
import { ValidatorFn, AbstractControl } from '@angular/forms';
import { FormGroup } from '@angular/forms';

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

  patternValidator(): ValidatorFn {
    return (control: AbstractControl): { [key: string]: any } =&gt; {
      if (!control.value) {
        return null;
      }
      const regex = new RegExp('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9]).{8,}$');
      const valid = regex.test(control.value);
      return valid ? null : { invalidPassword: true };
    };
  }

  MatchPassword(password: string, confirmPassword: string) {
    return (formGroup: FormGroup) =&gt; {
      const passwordControl = formGroup.controls[password];
      const confirmPasswordControl = formGroup.controls[confirmPassword];

      if (!passwordControl || !confirmPasswordControl) {
        return null;
      }

      if (confirmPasswordControl.errors &amp;&amp; !confirmPasswordControl.errors.passwordMismatch) {
        return null;
      }

      if (passwordControl.value !== confirmPasswordControl.value) {
        confirmPasswordControl.setErrors({ passwordMismatch: true });
      } else {
        confirmPasswordControl.setErrors(null);
      }
    }
  }

  userNameValidator(userControl: AbstractControl) {
    return new Promise(resolve =&gt; {
      setTimeout(() =&gt; {
        if (this.validateUserName(userControl.value)) {
          resolve({ userNameNotAvailable: true });
        } else {
          resolve(null);
        }
      }, 1000);
    });
  }

  validateUserName(userName: string) {
    const UserList = ['ankit', 'admin', 'user', 'superuser'];
    return (UserList.indexOf(userName) &gt; -1);
  }
}</code></pre><p>O método <code>patternValidator</code> é usado para validar o padrão de senha em nosso formulário. O parâmetro para este método é o tipo <code>AbstractControl</code>, que é uma classe base para <code>FormControl</code>.</p><p>Usaremos uma expressão regular para validar a senha. Validaremos as quatro condições a seguir usando a expressão regular:</p><ul><li>A senha deve ter um mínimo de oito caracteres.</li><li>Precisa ter pelo menos uma letra minúscula.</li><li>Precisa ter pelo menos uma letra maiúscula.</li><li>Precisa ter pelo menos um número.</li></ul><p>Se a senha falhar na verificação pela regex, definiremos a propriedade <code>invalidPassword</code> como verdadeira.</p><p>O método <code>MatchPassword</code> é usado para comparar as senhas em dois campos. Este método aceitará dois parâmetros do tipo String. Estes parâmetros representam o nome dos campos a serem correspondidos. Pegaremos o &nbsp;<code>FormControl</code> para esses dois campos e, em seguida, igualaremos os valores neles. Se os valores não coincidirem, definiremos a propriedade <code>passwordMismatch</code> como verdadeira.</p><p>O método <code>userNameValidator</code> é usado para verificar se o nome de usuário já foi usado anteriormente ou não. Este método aceitará um parâmetro do tipo <code>AbstractControl</code>. Verificaremos se o valor deste campo está presente em um array estático, <code>UserList</code>. Se o valor inserido pelo usuário já estiver presente, definiremos a &nbsp;propriedade <code>userNameNotAvailable</code> como verdadeira.</p><p>Estamos usando a função <code>setTimeout</code> para executar esta verificação a cada dois segundos. Isso garantirá que o erro será acionado após dois segundos a partir do momento em que o usuário parar de digitar no campo.</p><blockquote>Para simplificar este artigo, estamos usando um array estático para pesquisar a disponibilidade de nomes de usuário. Idealmente, deveria ser uma chamada de serviço ao servidor para pesquisar o valor em um banco de dados.</blockquote><h2 id="criando-o-componente-reactive-form"><strong>Criando o componente</strong> reactive-form</h2><p>Execute o seguinte comando para criar o componente &nbsp;reactive-form: </p><pre><code>ng g c reactive-form</code></pre><p>Abra <code>reactive-form.component.ts</code> e cole o código abaixo:</p><pre><code class="language-js">import { Component, OnInit } from '@angular/core';
import { Validators, FormGroup, FormBuilder } from '@angular/forms';
import { CustomvalidationService } from '../services/customvalidation.service';

@Component({
  selector: 'app-reactive-form',
  templateUrl: './reactive-form.component.html',
  styleUrls: ['./reactive-form.component.scss']
})
export class ReactiveFormComponent implements OnInit {

  registerForm: FormGroup;
  submitted = false;

  constructor(
    private fb: FormBuilder,
    private customValidator: CustomvalidationService
  ) { }

  ngOnInit() {
    this.registerForm = this.fb.group({
      name: ['', Validators.required],
      email: ['', [Validators.required, Validators.email]],
      username: ['', [Validators.required], this.customValidator.userNameValidator.bind(this.customValidator)],
      password: ['', Validators.compose([Validators.required, this.customValidator.patternValidator()])],
      confirmPassword: ['', [Validators.required]],
    },
      {
        validator: this.customValidator.MatchPassword('password', 'confirmPassword'),
      }
    );
  }

  get registerFormControl() {
    return this.registerForm.controls;
  }

  onSubmit() {
    this.submitted = true;
    if (this.registerForm.valid) {
      alert('Form Submitted succesfully!!!\n Check the values in browser console.');
      console.table(this.registerForm.value);
    }
  }
}</code></pre><p>Criaremos a variável <code>registerForm</code> do tipo <code>FormGroup</code>. No método <code>ngOnInit</code>, estabeleceremos os controles para o formulário usando a classe <code>FormBuilder</code>. Todos os campos são definidos como um campo obrigatório para este formulário. Chamaremos o método <code>userNameValidator</code> do serviço usando a função <code>bind</code>.</p><p>Para o campo de senha, usaremos o método de composição para mesclar em vários validadores em uma única função. Também invocaremos o método <code>MatchPassword</code> e passaremos o nome de <code>password</code> e <code>confirmPassword</code> como parâmetros.</p><p>A propriedade <code>registerFormControl</code> retornará os controles de formulário. O método <code>onSubmit</code> imprimirá o conteúdo do formulário no console se o formulário for válido e enviado com sucesso.</p><p>Agora, abra <code>reactive-form.component.html</code> e cole nele o código a seguir:</p><pre><code class="language-html">&lt;div class="container"&gt;
    &lt;div class="row"&gt;
        &lt;div class="col-md-8 mx-auto"&gt;
            &lt;div class="card"&gt;
                &lt;div class="card-header"&gt;
                    &lt;h3&gt;Angular Reactive Form&lt;/h3&gt;
                &lt;/div&gt;
                &lt;div class="card-body"&gt;
                    &lt;form class="form" [formGroup]="registerForm" (ngSubmit)="onSubmit()"&gt;
                        &lt;div class="form-group"&gt;
                            &lt;label&gt;Name&lt;/label&gt;
                            &lt;input type="text" class="form-control" formControlName="name"&gt;
                            &lt;span class="text-danger"
                                *ngIf="(registerFormControl.name.touched || submitted) &amp;&amp; registerFormControl.name.errors?.required"&gt;
                                Name is required
                            &lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class="form-group"&gt;
                            &lt;label&gt;Email&lt;/label&gt;
                            &lt;input type="text" class="form-control" formControlName="email"&gt;
                            &lt;span class="text-danger"
                                *ngIf="(registerFormControl.email.touched || submitted) &amp;&amp; registerFormControl.email.errors?.required"&gt;
                                Email is required
                            &lt;/span&gt;
                            &lt;span class="text-danger"
                                *ngIf="registerFormControl.email.touched &amp;&amp; registerFormControl.email.errors?.email"&gt;
                                Enter a valid email address
                            &lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class="form-group"&gt;
                            &lt;label&gt;User Name&lt;/label&gt;
                            &lt;input type="text" class="form-control" formControlName="username"&gt;
                            &lt;span class="text-danger"
                                *ngIf="(registerFormControl.username.touched || submitted) &amp;&amp; registerFormControl.username.errors?.required"&gt;
                                User Name is required
                            &lt;/span&gt;
                            &lt;span class="text-danger"
                                *ngIf="registerFormControl.username.touched &amp;&amp; registerFormControl.username.errors?.userNameNotAvailable"&gt;
                                User Name is not available
                            &lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class="form-group"&gt;
                            &lt;label&gt;Password&lt;/label&gt;
                            &lt;input type="password" class="form-control" formControlName="password"&gt;
                            &lt;span class="text-danger"
                                *ngIf="(registerFormControl.password.touched || submitted) &amp;&amp; registerFormControl.password.errors?.required"&gt;
                                Password is required
                            &lt;/span&gt;
                            &lt;span class="text-danger"
                                *ngIf="registerFormControl.password.touched &amp;&amp; registerFormControl.password.errors?.invalidPassword"&gt;
                                Password should have minimum 8 characters, at least 1 uppercase letter, 1 lowercase
                                letter and 1 number
                            &lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class="form-group"&gt;
                            &lt;label&gt;Confirm Password&lt;/label&gt;
                            &lt;input type="password" class="form-control" formControlName="confirmPassword"&gt;
                            &lt;span class="text-danger"
                                *ngIf="(registerFormControl.confirmPassword.touched || submitted)&amp;&amp; registerFormControl.confirmPassword.errors?.required"&gt;
                                Confirm Password is required
                            &lt;/span&gt;
                            &lt;span class="text-danger"
                                *ngIf="registerFormControl.confirmPassword.touched &amp;&amp; registerFormControl.confirmPassword.errors?.passwordMismatch"&gt;
                                Passwords doesnot match
                            &lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class="form-group"&gt;
                            &lt;button type="submit" class="btn btn-success"&gt;Register&lt;/button&gt;
                        &lt;/div&gt;
                    &lt;/form&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;</code></pre><p>Criaremos um reactive-form e usaremos o card do Bootstrap para a estilização. O cabeçalho do nosso card terá um título, enquanto o corpo terá os campos do formulário. Vincularemos a propriedade <code>formGroup</code> da tag &nbsp;<code>&lt;form&gt;</code> ao nome do nosso formulário, que é <code>registerForm</code>. O método <code>onSubmit</code> será invocado ao enviar o formulário. Também vincularemos a &nbsp;propriedade <code>formControlName</code> de cada campo de entrada ao nome de controle do nosso <code>FormGroup</code>. Verificaremos se há erros nos controles do formulário e, em seguida, exibiremos a mensagem de erro de validação apropriada na tela. </p><p>Execute o seguinte comando para criar o componente nav-bar:</p><pre><code>ng g c nav-bar</code></pre><p>Abra <code>nav-bar.component.html</code> e cole o código abaixo:</p><pre><code class="language-html">&lt;nav class="navbar navbar-expand-sm navbar-dark bg-dark fixed-top"&gt;
    &lt;a class="navbar-brand" [routerLink]='["/"]'&gt;Form Validation Demo&lt;/a&gt;
    &lt;div class="collapse navbar-collapse"&gt;
        &lt;ul class="navbar-nav mr-auto"&gt;
            &lt;li class="nav-item"&gt;
                &lt;a class="nav-link" [routerLink]='["/reactive-form"]'&gt;Reactive Form&lt;/a&gt;
            &lt;/li&gt;
        &lt;/ul&gt;
    &lt;/div&gt;
&lt;/nav&gt;</code></pre><p>Estamos adicionando o link de navegação ao componente da reactive-form na barra de navegação. </p><h2 id="atualizando-o-componente-do-aplica-o"><strong>Atualizando o componente do aplicação</strong></h2><p>Abra o arquivo <code>app.component.html</code> e cole nele o código abaixo:</p><pre><code class="language-html">&lt;app-nav-bar&gt;&lt;/app-nav-bar&gt;
&lt;div class="container"&gt;
  &lt;router-outlet&gt;&lt;/router-outlet&gt;
&lt;/div&gt;</code></pre><h2 id="atualizando-o-m-dulo-da-aplica-o"><strong>Atualizando o módulo da aplicação</strong></h2><p>Adicione o código a seguir no arquivo <code>app.module.ts</code>. Vamos importar o módulo de formulários e definir o roteamento para nossa aplicação. Você pode consultar <a href="https://github.com/AnkitSharma-007/angular-forms-validation/blob/master/src/app/app.module.ts">GitHub</a> para obter o código-fonte completo deste arquivo.</p><pre><code class="language-js">import { RouterModule } from '@angular/router';
import { ReactiveFormsModule } from  '@angular/forms';

@NgModule({
  ...    
  imports: [
    ...
    ReactiveFormsModule,
    RouterModule.forRoot([
      { path: '', component: ReactiveFormComponent },
      { path: 'reactive-form', component: ReactiveFormComponent }
    ]),
  ],
})</code></pre><h2 id="demonstra-o-da-execu-o"><strong>Demonstração da execução</strong></h2><p>Usaremos o comando abaixo para iniciar o servidor:</p><pre><code>ng serve -o</code></pre><p>Este comando iniciará a aplicação no seu navegador. Caso não abra automaticamente, você pode digitar <code>http://localhost:4200/</code> na barra do seu navegador. Você pode realizar todas as validações de formulário que vimos aqui.</p><p>Esta aplicação também está hospedada em <a href="https://ng-forms-validation.herokuapp.com/">https://ng-forms-validation.herokuapp.com/</a>. Navegue até o link e faça alguns testes para uma melhor compreensão.</p><h2 id="resumo"><strong>Resumo</strong></h2><p>Criamos um modelo de formulário de registro de usuário utilizando a abordagem reactive-form no Angular. Também implementamos as validações integradas e personalizadas no formulário. Por fim, utilizamos a biblioteca do Bootstrap para a estilização. </p><p>Você pode obter o código-fonte no <a href="https://github.com/AnkitSharma-007/angular-forms-validation">GitHub</a> e fazer alguns testes para uma melhor compreensão.</p><p>Você pode encontrar outras publicações como esta no blog do autor, <a href="https://ankitsharmablogs.com/">Ankit Sharma</a> <em>(em inglês)</em>.</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
