DEV Community 👩‍💻👨‍💻

Lucas Paganini for Lucas Paganini PT

Posted on

O Que há De Novo No Angular 14 - Uma Mudança De Jogo

Introdução

O Angular 14 foi lançado recentemente com vários recursos interessantes. E hoje, vou apresentá-los para você. São eles:

  1. Standalone Components
  2. Provedores de rota
  3. ENVIRONMENT_INITIALIZER
  4. Formulários tipados
  5. A Função inject()
  6. Configuração do título da página pela rota
  7. Autocomplete na CLI
  8. Injetores opcionais em Embedded Views

Então vamos começar!

Standalone components

Para a maioria das pessoas, a mudança mais significativa nesta versão é a possibilidade de criar componentes sem @NgModule! Sim, Isso mesmo que você leu.

https://i.makeagif.com/media/8-08-2022/Em_2-b.gif

Antes do Angular 14

Se você está um pouco perdido, me deixe te mostrar uma estrutura de diretório para um componente clássico do angular:

home
|--home.component.html
|--home.component.css
|--home.component.ts
|--home.module.ts
Enter fullscreen mode Exit fullscreen mode

Nela, temos um arquivo .html para o template, um arquivo .css para os estilos, um arquivo .ts para o componente e outro arquivo .ts para o @NgModule. Este último arquivo importa as dependências do nosso componente, declara o componente e também pode definir alguns provedores.

Uma nova possibilidade com Angular 14

No Angular 14, podemos fazer tudo isso diretamente no componente, sem precisar de um @NgModule.

home
|--home.component.html
|--home.component.css
|--home.component.ts
Enter fullscreen mode Exit fullscreen mode

Para fazer isso, basta definir a propriedade standalone em nosso componente como true.

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss'],
  standalone: true,
})
Enter fullscreen mode Exit fullscreen mode

Fique atento!

Fique atento:

  1. Standalone Component não é a nova maneira de declarar componentes! Ele é outra maneira de declarar componentes. A forma clássica de definir @NgModules não será obsoleta.

Bem, eu realmente não posso prometer que não será obsoleto. Mas sim, até agora, não há intenções de depreciar os @NgModules.

De fato. Ainda usarei @NgModules em vez de standalone components porque gosto do isolamento que @NgModules fornece.

  1. Não migre todo o seu aplicativo para standalone components ainda! Eles são muito recentes e levaremos um tempo para criar convenções e definir as melhores práticas. Recomendo esperar um pouco mais antes de pular de cabeça nessa nova possibilidade.

Provedores de rotas

Mas ei, se abandonarmos o @NgModule e usarmos standalone components, como podemos definir o provedor por rota, como costumávamos fazer com @NgModules?

Para resolver isso, o Angular adicionou provedores de rotas. Então, basicamente, as definições de rota agora têm uma propriedade chamada providers. Permitindo-nos fornecer valores apenas para os módulos e componentes renderizados por essa rota.

const NAME = new InjectionToken<string>('token');

export const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    providers: [
      {
        provide: NAME,
        useValue: 'foo',
      },
    ],
  }
];
Enter fullscreen mode Exit fullscreen mode

ENVIRONMENT_INITIALIZER

(INICIALIZADOR DE AMBIENTE)

Outra coisa que costumávamos fazer com NgModules era executar um script de configuração quando um módulo carregado com lazy load era inicializado. Em outras palavras, o constructor de um módulo carregado com lazy load só seria executado quando o módulo fosse inicializado, e alguns desenvolvedores aproveitam isso para executar algum tipo de configuração.

export class HomeModule {
  constructor(){
    console.log("You can run something here")
  }
}
Enter fullscreen mode Exit fullscreen mode

Como podemos fazer isso com standalone components? A solução é usar o token ENVIRONMENT_INITIALIZER.

const routes: Routes = [
  {
    path: '',
    pathMatch: 'full',
    component: HomeComponent
    providers:[
      {
        provide: ENVIRONMENT_INITIALIZER,
        multi: true,
        useValue: () => console.log("You can run something right here too")
      }
    ]
  }
]
Enter fullscreen mode Exit fullscreen mode

Esse token nos permite fornecer uma função de configuração que será executada antes que o ambiente seja inicializado.

Se quisermos que ele seja executado quando navegarmos para uma rota, podemos fornecer esse token usando provedores de rota.

Isso tem o mesmo efeito que nossa solução anterior usando NgModule constructors e tem o benefício adicional de ser mais explícito.

Formulários Tipados

Outro recurso muito aguardado do Angular 14 são os formulários tipados.

Antes da versão 14, os valores de formulário eram tipados como any. Isso significa que perdiamos toda a incrível segurança de tipagem do TypeScript.

const control = new FormControl(""),
control.value
//=> control.value: any
Enter fullscreen mode Exit fullscreen mode

A propósito, existe uma maneira segura de dizer que você não conhece o tipo de algo. Se você estiver interessado nisso, confira este vídeo de um minuto explicando as diferenças entre any e unknown.

De qualquer forma, não temos mais esse problema. Porque o Angular 14 tem tipos estritos para formulários. Portanto, se um FormControl lidar com uma string, o valor será tipado como uma string em vez de any.

const control = new FormControl(""),
control.value
//=> control.value: string | null
Enter fullscreen mode Exit fullscreen mode

Funções injetáveis

Agora, esta é a característica mais interessante para mim.

Angular 14 introduziu as funções injetáveis. E se parecem muito com os React hooks. Isso nos dá um universo de possibilidades para reutilizar nosso código, a mais relevante é que agora podemos criar funções reutilizáveis que usam injeção de dependência internamente.

export function getPosts() {
  const http = inject(HttpClient);
  return http.get('/api/getPosts');
}

export class HomeComponent {
  readonly posts = getPosts();
}
Enter fullscreen mode Exit fullscreen mode

Se você está tão interessado em programação funcional quanto eu, sabe que isso significa muito! Mas como o tio Ben disse uma vez:

"Com grandes poderes vem grandes responsabilidades”

Isso cria dependências implícitas em nossa função. No entanto, espero que minhas dependências de função sejam declaradas explicitamente nos argumentos da função. Então, se vejo uma função sem argumentos, imagino que ela não tenha dependências. Mas agora, podemos criar funções que parecem puras, porém injetam muitas dependências internamente, tornando-as mais difíceis de testar e mais acopladas ao framework Angular.

Uma boa solução é seguir a mesma convenção que temos no React, prefixar essas funções com “use”. Dessa forma, você pode identificar facilmente funções que usam inject() internamente.

export function useGetPosts() {
  const http = inject(HttpClient);
  return http.get('/api/getPosts');
}

export class HomeComponent {
  readonly posts = useGetPosts();
}
Enter fullscreen mode Exit fullscreen mode

Definir o título da página pela rota.

Uma tarefa comum em aplicações Web é alterar o título da página em cada rota.

No Angular, isso costumava ser um processo muito manual, mas agora podemos simplesmente definir o título da página na definição da rota.

export const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    title: 'Home',
    pathMatch: 'full',
  },
];
Enter fullscreen mode Exit fullscreen mode

Mas eu sei o que você está pensando:

"Lucas, não consigo definir o título na definição da rota porque meu título não é estático, depende de algo que recebo da minha API".

Não se preocupe. Angular 14 pensou em você.

Se você precisar personalizar o título dinamicamente, poderá fazê-lo estendendo a classe TitleStrategy do @angular/router e fornecer sua nova estratégia de título personalizada em vez da padrão.

@Injectable({ providedIn: 'root' })
export class PageTitleStrategy extends TitleStrategy {
  constructor(@Inject(Title) private title: Title) {
    super();
  }

  override updateTitle(routerState: RouterStateSnapshot) {
    const title = this.buildTitle(routerState);
    if (title !== undefined) {
      this.title.setTitle(`CompanyName | ${title}`);
    } else {
      this.title.setTitle(`CompanyName | Page without title`);
    }
  }
}

export const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    title: 'Home',
    pathMatch: 'full',
  },
];

bootstrapApplication(AppComponent, {
  providers: [
    importProvidersFrom(RouterModule.forRoot(routes)),
    { provide: TitleStrategy, useClass: PageTitleStrategy },
  ],
});
Enter fullscreen mode Exit fullscreen mode

Angular CLI Autocomplete

Outra coisinha legal é que agora temos um autocomplete na CLI do Angular.

Basta digitar ng no seu terminal e pressionar TAB para permitir que a CLI do Angular complete automaticamente seu comando ou forneça ajuda.

> ng se
//=> If you press TAB here, the CLI will complete

> ng serve
Enter fullscreen mode Exit fullscreen mode
> ng 
//=> If you press TAB here, the CLI will show a list of commands

> ng
    add           -- Adds support for an external library to your project.
    analytics     -- Configures the gathering of Angular CLI usage metrics. 
    build         -- Compiles an Angular application or library into an outpu...
    cache         -- Configure persistent disk cache and retrieve cache sta...
    ...
Enter fullscreen mode Exit fullscreen mode

Ativando o autocomplete da CLI

Para ativá-lo, você deve executar o comando ng complete e confirmar que deseja habilitar o autocomplete digitando Yes.

> ng completion

? Would you like to enable autocompletion? This will set up your terminal so pressing 
TAB while typing Angular CLI commands will show possible options and autocomplete arguments.
(Enabling autocompletion will modify configuration files in your home directory.)

> Yes
Enter fullscreen mode Exit fullscreen mode

Por fim, reinicie seu terminal para ativar o autocomplete.

Injetores opcionais em Embedded Views

Por último, mas não menos importante, agora podemos passar injetores opcionais em embedded views. No passado, tínhamos que usar outras APIs para fazer isso, como o ngComponentOutlet.

@Directive({ selector: '[foo]' })
export class FooDirective implements OnInit {
  constructor(
    private vcr: ViewContainerRef,
    private templateRef: TemplateRef<unknown>
  ) {}

  ngOnInit(): void {
    this.vcr.createEmbeddedView(
      this.templateRef,
      {}, // context
      {
        injector: Injector.create({ // pass an injector :)
          providers: [
            {
              provide: 'foo',
              useValue: 'bar',
            },
          ],
        }),
      }
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Não pare aqui

Essas foram as mudanças mais relevantes no Angular 14, na minha opinião. Se você quiser ver todas as alterações, você poderá vê-las verificando as referências.

Se você quiser se aprofundar no Angular, considere assinar nossa newsletter em lucaspaganini.com. É livre de spam e Mantemos os e-mails curtos e com conteúdo valioso.

E se sua empresa estiver procurando por desenvolvedores web remotos, considere entrar em contato comigo e minha equipe. Você pode fazer isso em lucaspaganini.com.

Como sempre, as referências estão na descrição. Tenha um ótimo dia. E te vejo na próxima.

– Lucas

Referências

  1. Angular 14 - Academind on Youtube
  2. O que há de novo no revolucionário Angular 14 - Andrew Rosário on Medium
  3. Novidades no Angular v14 - Vida Fullstack
  4. What is new in Angular 14? - Nevzatopcu on Medium
  5. Angular v14 is now available! - Angular Blog on Medium
  6. What’s New in Angular v14 - Netanel Basal
  7. Unleash the Power of DI Functions in Angular - Netanel Basal
  8. Getting to know the ENVIRONMENT_INITIALIZER Injection Token in Angular - Netanel Basal
  9. Typed Reactive Forms in Angular — No Longer a Type Dream - Netanel Basal
  10. Handling Page Titles in Angular - Netanel Basal
  11. Angular Standalone Components: Welcome to a World Without NgModule - Netanel Basal
  12. Pass an Injector to Embedded Views - Netanel Basal
  13. Setting page title from the route module - Brandon Roberts
  14. Standalone components with Custom Title Strategy in Angular 14

Top comments (0)

Update Your DEV Experience Level:

Settings

Go to your customization settings to nudge your home feed to show content more relevant to your developer experience level. 🛠