Telerik blogs

Read about all the highlights included in Angular 16.

Yeah, I know I got you with the title, right? If you are still wondering what the buzz is all about, first, the biggest release since the initial rollout of Angular (quoting Minko Gechev in the astonishing official Angular release blogpost) happened, and then it happened on May 3. Which is so close to May 4 (as in May the Fourth be with you), hence the sounds made when slicing the air holding a Kyber crystal charged blade.

Despite being a Star Wars fan, I am not going to speculate on how exactly one should spell the sound a lightsaber makes. Instead, I’ll focus on the many cool highlights from Angular 16 release, and then go over the current hottest concept of signals. While the ones below do not comprise the entire list of features and improvements, it is worth starting with:

  • New reactivity primitives—enter signals first developer preview
  • Non-destructive hydration developer preview
  • CLI’s new builder on esbuild
  • Auto-import components and pipes of the Angular language service
  • Support for Typescript 5.0 and ECMAScript decorators
  • Standalone new schematics, migration schematics and standalone migration guide

Also, I can’t skip the ease of life brought to anyone that gets their hands on Angular with the introduction of:

  • Mark component and directive inputs as required
  • Pass route data, path and query params to a routing component’s inputs
  • Injectable OnDestroy
  • Self-closing component tags

On the security and accessibility front the Angular Team continues to improve and expand:

  • CSP support for inline styles (also in the CLI) with the nonce attribute specification
  • Angular components’ accessibility (check what’s closed so far here)

Before You Deep Dive

After reading about all the cool stuff coming with Angular 16, I’d bet you’d be trying to update your app at earliest convenience, but it is reading time first (and trust me, it is always for the better).

Complete Changelogs on:

Notable Breaking Changes Like:

  • Node.js 14 support removed; Node.js v16 or v18 required
  • TypeScript 4.8 support dropped; Typescript version 4.9 or later is required
  • Angular Compatibility Compiler (ngcc) removed
  • ReflectiveInjector and related symbols removed
  • Angular Package Format flattened ESM 2015 (FESM2015) outputs removed
  • EcmaScript 2020 outputs updated to EcmaScript 2022 (including the flattened output)
  • Router.createUrlTree updated—attention if you mock ActivatedRoute

So, I guess that’s the only thing that stands between you and the new version of your Angular app, in addition to some more reading, refactoring, unit and regression testing, debugging then reading and coding again, but that’s the beauty of it after all. Fun part aside, as with any brand new and experimental features, caution is required first, so better be safe than sorry.

Up until that moment everything indicates that Angular 16 would be a game or life (or both) changer. Thus, I’d personally update all my Kendo UI for Angular apps that I use in my daily job, gradually and one module at a time. I know Kendo Angular comes with day one support for every notable framework release, so it’s all in my hands now. And while doing so, I’d be more than happy to let you all know and blog about or even equally provoke and inspire my amazing and fun colleague Alyssa Nicoll to do it.

two kendoka sparring

Actually, I Quickly Played with the Non-Destructive Hydration

Up until now with server-side rendering in Angular, the app DOM was completely destroyed when the client was bootstrapped. This meant flickering after the page was rendered and before it was interacted with. No more workarounds for this or negative impact on the CLS and LCP Core Web Vitals; as with Angular 16, the server renders the app and when the client is bootstrapped, it reuses existing DOM structures. Hence, it’s not a necessity to destroy all of them. In addition, requests made on the server are cached, so re-fetching same data on the client is not a thing now.

Judging by the Angular 2023 Roadmap, server-side rendering improvements are a significant effort. Which is great for me, because my fully native apps that use Angular Universal and are built with Kendo UI for Angular will directly get them. I was eager to play with a Kendo Node.js app by following the official guide by Angular team:

Update (bolded below) app.module.ts file:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import {provideClientHydration} from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { TransferHttpCacheModule } from '@nguniversal/common';
import { GridModule } from '@progress/kendo-angular-grid';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
declarations: [
AppComponent,
HomeComponent,
],
imports: [
BrowserAnimationsModule,
BrowserModule.withServerTransition({ appId: 'serverApp' }),
RouterModule.forRoot([
{ path: '', component: HomeComponent, pathMatch: 'full' },
{ path: 'lazy', loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule) },
{ path: 'lazy/nested', loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule) }
]),
TransferHttpCacheModule,
GridModule
],
providers: [ provideClientHydration() ],
bootstrap: [AppComponent]
})
export class AppModule { }

Note that with hydration, having identical DOM structures on both server and client is a must, so include provideClientHydration() into the respective providers when bootstrapping on the server. Any mismatch would result in errors whether these are caused by a non-valid HTML structure or directly manipulating the DOM with browser APIs. You’d like to omit hydration for a component and its tree by using ngSkipHydration in such case:

@Component({ 

  ... 

 host: {ngSkipHydration: 'true'}, 

}) 

And that’s it. Whether my app would now be quicker than a cheetah on rollerblades is something that I‘d certainly not speculate on yet, because playing with new features on dev environment is cool but applying these early on production is a whole other story.

Part 2 of This Blogpost Would be New Signal Feature Explained—the Simple Way!

That’s something I like to do on every occasion as I believe the time spent on understanding new stuff, even if you have to start from AB, pays out significantly in time. Or it could be said, invest more time to save even more time (no pun intended).

What’s The Story Around Signals?

Essentially, a signal is a distinctive type of variable that stores a value, with the added benefit of providing alerts (i.e., notify all dependent nodes), when the value of the variable is modified.

Or I can refer you to the Angular Team’s definitionA signal is value with explicit change semantics, represented by a zero-argument getter function returning the current signal value:

interface Signal<T> { 

  (): T; 

  [SIGNAL]: unknown; 

} 

Or I can refer you to Alex Rickabaugh’s comment—A Signal is a source of value.

It is all about state management and introducing a more lightweight and flexible approach to change detection (and more specifically, per component detection). Signals can be either writable or computed. The former get their values updated by mutation API. The latter are read only and derive their values from other signals. You can use them in components, templates, services, directives and whatnot.

Though it’s already been used in some other libraries, the adoption of this reactive mechanism by Angular is already positioning signals as a major culprit for an innovator slash game changer, replacement of RxJS, Zone.js or a reason to rethink NgRX best practices. But for the time being signals remain an option, so you don’t have to change anything if you are not ready to.

I decided to play (I really mean play, you can judge by the not so creative item names) with signals in a Kendo Angular Grid. Updating to Angular 16 took care of all necessary imports; I just added this in order to use it for the grid.

 import { Component, signal } from '@angular/core'; 

Here is how app.components.ts file looks:

import { Component, signal } from '@angular/core'; 



@Component({ 

  selector: 'app-root', 

  templateUrl: './app.component.html', 

  styleUrls: ['./app.component.css'], 

}) 

export class AppComponent { 

  public gridData = signal([ 

    { 

      ProductID: 1, 

      ProductName: 'Chai', 

      UnitPrice: 18, 

      Category: { 

        CategoryID: 1, 

        CategoryName: 'Beverages', 

      }, 

    }, 

    { 

      ProductID: 2, 

      ProductName: 'Chang', 

      UnitPrice: 19, 

      Category: { 

        CategoryID: 1, 

        CategoryName: 'Beverages', 

      }, 

    }, 

  ]); 

  public categories: Category[] = [ 

    { CategoryID: 1, CategoryName: 'Beverages' }, 

    { CategoryID: 2, CategoryName: 'Condiments' }, 

    { CategoryID: 3, CategoryName: 'Confections' }, 

    { CategoryID: 4, CategoryName: 'Dairy Products' }, 

    { CategoryID: 5, CategoryName: 'Grains/Cereals' }, 

    { CategoryID: 6, CategoryName: 'Meat/Poultry' }, 

    { CategoryID: 7, CategoryName: 'Produce' }, 

    { CategoryID: 8, CategoryName: 'Seafood' }, 

  ]; 

  public updateData() { 



    this.gridData.mutate((gridData) => { 

      gridData.push(this.generateRandomUser()); 

    }); 

  } 

  public getRandomItem<T>(array: T[]): T { 

    const index = Math.floor(Math.random() * array.length); 

    return array[index]; 

  } 

  public generateRandomUser(){ 

    const product: Product = { 

        ProductID: Math.floor(Math.random() * 500), 

        ProductName: 'Product ' + Math.floor(Math.random() * 100), 

        UnitPrice: Math.floor(Math.random() * 100), 

        Category: this.getRandomItem(this.categories), 

      }; 

      return product; 

  } 

} 

type Category = { 

    CategoryID: number; 

    CategoryName: string; 

  }; 



  type Product = { 

    ProductID: number; 

    ProductName: string; 

    UnitPrice: number; 

    Category: Category; 

  }; 

The idea is to call a function generating a random object and add it to the grid collection.

Before signals, we had to change the reference to the collection:

gridData.push(this.generateRandomUser()); 

this.gridData =[...this.gridData]; 

Which ultimately triggered change detection going through the entire tree.

After signals, only the Grid is updated and mutate() takes care of changing the UI.

this.gridData.mutate((gridData) => { 

      gridData.push(this.generateRandomUser()); 

Here’s how it looks:

And that’s it. If you’d like to get familiar with the entire concept of signals in Angular, I’d refer to the four parts RFC from Angular:

Some Words on CSP Updates in Angular 16

While the topic of security in modern web development is a worthy candidate for a separate post or a series of such or let’s be honest—a weighty tome, I’d like to praise the Angular Team for the latest updates on the matter.

From Enterprise point of view, inline scripting has always been a concern when it could be marked as unsafe, hence the Content Security Policy (CSP) to negate XSS (Cross Site Scripting). Angular 16 introduces a nonce attribute (available in Framework, CLI, CDK, Material and Universal) that allows you to set CSP for inline styles.

Specifying it can be done by ngCspNonce attribute on the app root which is quite beneficial if you have access to server-side templating or by using the CSP_NONCE injection token if you have access to the nonce at runtime.

Folks like me using Kendo UI in Angular apps would directly benefit from this feature, pursuing the goal to be CSP compatible and ultimately ensure strict CSP compliance. In addition to that, the own 2023 Kendo UI for Angular 2023 Roadmap includes replacement of all font icons internally used with SVG icons in order to address the font-src directive and detaching font-related CSS from Kendo themes to remove the need for the font-src directive.

May the Force be with you, and till next time!


About the Author

Petar Grigorov

Petar is a Principal Sales Engineer at Progress with equal sympathy in coding and automation testing. In his spare time he turns into a DIY guy who can successfully setup and use anything from IoT gadgets to paintbrushes and a trowel. When not dreaming of piloting the Millennium Falcon, he is a fan of any engine that is close enough and runs on two or four wheels.

Related Posts

Comments

Comments are disabled in preview mode.