Angular 19: What's new
🎉 Angular 19 has arrived, and it's set to revolutionize how we build web applications! This major release brings a host of new features, let's dive into what makes Angular 19 a game-changer.
1. Add routerOutletData
input to RouterOutlet
directive (#57051)
When you set the routerOutletData
input on a RouterOutlet
, the provided value becomes available to the child component injectors through the ROUTER_OUTLET_DATA
token. What makes this feature particularly powerful is its use of Angular's signal system.
The ROUTER_OUTLET_DATA
token uses a Signal
type. This means that the input value can be updated dynamically, and these updates will propagate to the token in real-time. This reactive approach allows for more flexible and responsive routing scenarios.
@Component({
selector: 'app-parent',
template: `
<router-outlet [routerOutletData]="outletData"></router-outlet>
`
})
export class ParentComponent {
outletData = signal({ theme: 'dark', userRole: 'admin' });
updateTheme(newTheme: string) {
this.outletData.update(currentData => ({
...currentData,
theme: newTheme
}));
}
}
@Component({
selector: 'app-child',
template: `
<p>Current theme: {{ theme() }}</p>
<p>User role: {{ userRole() }}</p>
`
})
export class ChildComponent {
private outletData = inject(ROUTER_OUTLET_DATA);
theme = computed(() => this.outletData().theme);
userRole = computed(() => this.outletData().userRole);
}
In this example, the ParentComponent
sets up a routerOutletData
input with some initial data. The ChildComponent
, which is rendered inside the RouterOutlet
, can then access this data using the ROUTER_OUTLET_DATA
token.
⚠️ While this feature offers great flexibility, it's important to use it judiciously. Over-reliance on routerOutletData
could lead to tightly coupled components. It's best used for passing down configuration or context that is genuinely shared and relevant across multiple child routes.
2. TypeScript 5.6 Support (#57424)
Disallowed Nullish and Truthy Checks: stricter checks for expressions that are always truthy or nullish:
if (x => 0) { // Error: This kind of expression is always truthy. }
Strict Builtin Iterator Checks
@Injectable({ providedIn: 'root' }) export class DataService { getFilteredData(): BuiltinIterator<number> { return Iterator.from([1, 2, 3, 4, 5]) .filter(x => x % 2 === 0) .map(x => x * 2); } }
Support for Arbitrary Module Identifiers: you can use string literals as export and import names:
// In an Angular module export { MyComponent as "⭐️" }; // In another file import { "⭐️" as StarComponent } from './my-component';
The --noUncheckedSideEffectImports Option
// This will now raise an error if the module doesn't exist import './styles.css';
The --noCheck Option: speed up compilation times by skipping type checking.
One of the coolest features I will use from here is consider enabling --strictBuiltinIteratorReturn
for improved type safety with iterators.
Learn more about TypeScript 5.6 changes here.
3. Enhanced NgOptimizedImage: Automatic 'sizes auto' for Responsive Images (#57479)
The NgOptimizedImage directive now automatically prepends 'auto' to the value of the sizes
attribute for images that meet the following criteria:
Have a responsive
srcset
Are lazy-loaded (not marked with
priority
)
When you use NgOptimizedImage with a responsive image, you typically provide a sizes
attribute to help the browser select the appropriate image size. For example:
<img ngSrc="example.jpg" width="100" height="100" sizes="50vw">
With this new feature, Angular will automatically modify the sizes
attribute to:
<img ngSrc="example.jpg" width="100" height="100" sizes="auto, 50vw">
The auto
value allows browsers to automatically calculate the rendered size of the image, potentially choosing a more appropriate image size from the srcset
.
Example 1 with ngSrcset provided:
<img ngSrc="example.jpg" width="100" height="100" ngSrcset="100w, 200w, 300w">
This will automatically set sizes="auto, 100vw"
:
<img ngSrc="example.jpg" fill sizes="50vw">
Example 2 that works with lazy loaded images:
<img ngSrc="example.jpg" fill sizes="50vw">
This will become sizes="auto, 50vw"
if the image is lazy-loaded.
Important Considerations
Priority Images: the 'auto' prefix is not added to images marked with
priority
or explicitly set toloading="eager"
.Existing Sizes: if a
sizes
attribute is already provided, NgOptimizedImage respects it and only prepends 'auto' if the image is lazy-loaded.Fill Mode: in fill mode, if no
sizes
is specified, NgOptimizedImage defaults to"auto, 100vw"
.Performance: this feature aims to improve performance by allowing browsers to automatically calculate the most appropriate image size, potentially reducing unnecessary data transfer.
4. Render default fallback with empty projectableNodes (
v19.0.0-next.2)
When passing an empty array to projectableNodes
in the createComponent
API, the default fallback content of the ng-content
will be rendered if present.
To prevent rendering the default content, pass document.createTextNode('')
as a projectableNode
.
For example:
// The first ng-content will render the default fallback content if present
createComponent(MyComponent. { projectableNodes: [[], [secondNode]] });
// To prevent projecting the default fallback content:
createComponent(MyComponent. { projectableNodes: [[document.createTextNode('')], [secondNode]] });
If you want to learn more about Fallback content in ng-content, here you can do it.
5. New Diagnostic: Unused Standalone Imports (#57605)
Angular now provides a warning for standalone imports that are declared in the imports
array but not used within the component. The Angular Language Service now offers an automatic fix for removing unused imports.
You can configure this feature in your tsconfig.json
file:
{
"angularCompilerOptions": {
"extendedDiagnostics": {
"checks": {
"unusedStandaloneImports": "warning" // or "error" or "suppress"
}
}
}
}
"warning"
: default behavior, shows a warning for unused imports."error"
: elevates the diagnostic to an error, potentially breaking the build."suppress"
: turns off the diagnostic completely.
The new diagnostic is identified as NG8113: Unused Standalone Imports
.
6. Experimental Feature: Migrating @Input()
to Signal Inputs (#57214)
When a developer clicks on an @Input
property declaration in their editor, they can invoke this refactoring action. The language service then:
Converts the
@Input()
decorator to a signal input.Updates all references to this input throughout the codebase.
Adjusts imports as necessary.
How to Use
Open your Angular component file in a supported editor (e.g., VS Code with the Angular Language Service extension).
Place your cursor on an
@Input()
declaration.Trigger the refactoring action (usually through a context menu or command palette).
Review the changes and confirm the refactoring.
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-example',
template: '{{message}}'
})
export class ExampleComponent {
// Before
@Input() message: string = 'Hello';
// After
message = input<string>('Hello');
}
7. Angular's New afterRenderEffect
Primitive (#57549)
The afterRenderEffect
API is similar to afterRender
and afterNextRender
, but with a crucial difference in how values are handled:
Signal Propagation: instead of passing plain values between phases,
afterRenderEffect
uses signals.Conditional Execution: later phases of the effect may not run if the signals from earlier phases haven't changed.
Reactive Chain: creates a chain of reactive computations that respond to changes in the DOM or application state.
You can read more here.
8. Angular Schematics: Migration to standalone: false
(#57643)
Angular has introduced a new schematics migration to help developers transition their existing non-standalone components to explicitly declare standalone: false
.
The migration automatically identifies components, directives, and pipes that are not explicitly marked as standalone.
It adds
standalone: false
to the decorator metadata of these identified elements.For components already marked as
standalone: true
, the migration removes this declaration.No Changes to Existing
standalone: false
: Components already explicitly set tostandalone: false
are not modified.The migration does not modify decorators that are empty (i.e.,
@Directive()
with no metadata).
How to use the migration:
ng update --migrate-only explicit-standalone-flag
Examples:
// Before
@Component({
selector: '[someComponent]'
})
export class SomeComponent {}
// After
@Component({
selector: '[someComponent]',
standalone: false // 👈
})
export class SomeComponent {}
// --------------------------
// Before
@Directive({
selector: '[someDirective]',
standalone: true // ❌
})
export class SomeDirective {}
// After
@Directive({
selector: '[someDirective]'
})
export class SomeDirective {}
9. Angular's Signal Input Migration Schematic (#57805)
Angular has introduced a new ng generate
schematic to automate the migration of traditional @Input()
declarations to the new signal inputs.
Key Features
Converts
@Input()
declarations to signal inputs.Handles not just the input declarations but also all references to these inputs throughout the application.
Can be run as an
ng generate
command.
To run the migration, use the following Angular CLI command:
ng generate @angular/core:signal-input-migration
Example:
import {Component, Input} from '@angular/core';
// Before
@Component({
template: `Name: {{name ?? ''}}`
})
export class MyComponent {
@Input() name: string|undefined = undefined;
someMethod(): number {
if (this.name) {
return this.name.length;
}
return -1;
}
}
// After
import {Component, input} from '@angular/core';
@Component({
template: `Name: {{name() ?? ''}}`
})
export class MyComponent {
name = input<string>();
someMethod(): number {
const name = this.name();
if (name) {
return name.length;
}
return -1;
}
}
Full Class Migration to Signal Inputs in VSCode (#57975)
Language Service allows developers to convert all @Input()
decorators in a class to signal inputs directly within Visual Studio Code.
The user can click on an class with `@Input`s and ask for all the input to be migrated.
10. Angular marks Input, Output, and Model APIs as Stable (#57804)
If you want to know more about this APIs I have a wonderful post about Signals here. Note that Output is not signal based.
11. Angular Stabilizes @let
Syntax in Templates (#57813)
This feature allows developers to define and reuse local variables across templates, similar to JavaScript's let
syntax.
Use Cases
Async Data Handling: ideal for managing asynchronous data streams in templates.
Complex Computations: useful for storing results of complex expressions for reuse.
Template Refactoring: helps in breaking down complex templates into more manageable parts.
Conditional Rendering: enhances readability in conditional rendering scenarios.
@let user = user$ | async;
@if (user) {
<h1>Hello, {{user.name}}</h1>
<user-avatar [photo]="user.photo"/>
<ul>
@for (snack of user.favoriteSnacks; track snack.id) {
<li>{{snack.name}}</li>
}
</ul>
<button (click)="update(user)">Update profile</button>
}
12. Changes at Effect Execution Timing (#57874)
Angular has implemented a major change in how effects are executed, which impacts both the timing of effect execution and how they interact with change detection. If you want to read more on how to avoid effect, or when to use them, do it here.
Key Changes
Change Detection Integration: effects triggered outside of change detection now run as part of the change detection process, rather than as a microtask.
Earlier Execution: effects triggered during change detection (e.g., by input signals) now run earlier, specifically before the component's template is processed.
Removal of
allowSignalWrites
: the allowSignalWrites option has been made a no-op (no operation), effectively removing its functionality.
@Component({...})
class MyComponent {
data = input<string>();
constructor() {
effect(() => {
console.log('Data changed:', this.data());
// This used to run after the template was processed
// Now runs before the template is processed
});
afterRenderEffect(() => {
// Use this for operations that need to occur after rendering
console.log('Rendered with data:', this.data());
});
}
}
As you can see in the example, the afterRenderEffect is a good tool for rendering DOM operations after the actual DOM has fully rendered.
13. Signal-Based Query APIs as Stable (#57921)
Signal-based query APIs in Angular allow developers to query and interact with the component's view and its children using signals.
If you want to learn more about this queries, do it here.
14. ExperimentalPendingTasks promotes to PendingTasks (#57533)
This change moves the service from an experimental status to a developer preview, indicating increased stability and readiness for wider adoption.
PendingTasks
is a service that helps manage and track asynchronous tasks that contribute to the application's stability. It's particularly useful for scenarios where custom asynchronous operations need to be factored into Angular's stability calculations.
import { Component, inject } from '@angular/core';
import { PendingTasks } from '@angular/core';
@Component({...})
export class MyComponent {
private pendingTasks = inject(PendingTasks);
async loadData() {
const taskId = this.pendingTasks.add();
try {
// Perform async operation
await this.dataService.fetchData();
} finally {
this.pendingTasks.remove(taskId);
}
}
}
This code sets up a mechanism to track an asynchronous operation within Angular's stability model. Here's what it accomplishes:
When
loadData()
is called, it immediately notifies Angular that a task is pending.It then performs an asynchronous operation (fetching data in this case).
Once the operation is complete (whether successful or not), it notifies Angular that the task is finished.
Why This Is Important:
Angular uses the concept of "stability" to determine when it's safe to do certain operations, like running change detection or resolving navigation.
By using
PendingTasks
, this component ensures that Angular doesn't consider the application stable whileloadData()
is in progress.This can be crucial for scenarios like server-side rendering, where you might want to wait for all data to be loaded before sending the rendered page to the client.
It also helps in testing scenarios, allowing you to wait for all async operations to complete before making assertions.
This pattern ensures that Angular has a complete picture of ongoing asynchronous work, leading to more predictable and manageable application behavior, especially in complex scenarios involving multiple asynchronous operations.
15. Angular Signal Queries Migration Schematic (#58032)
New schematic to automate the migration of decorator-based queries to signal-based queries. Converts @ViewChild
, @ViewChildren
, @ContentChild
, and @ContentChildren
decorators to their signal equivalents.
Handles not just the query declarations but also all references to these queries throughout the application.
To run the migration, use the following Angular CLI command:
ng generate @angular/core:signal-queries-migration
The migration updates query decorators to their signal equivalents:
@ViewChild()
→viewChild()
@ViewChildren()
→viewChildren()
@ContentChild()
→contentChild()
@ContentChildren()
→contentChildren()
For example:
import {Component, ContentChild, contentChild, ElementRef} from '@angular/core';
@Component({
template: `Has ref: {{someRef ? 'Yes' : 'No'}}`
})
export class MyComponent {
// Before
@ContentChild('someRef') ref: ElementRef|undefined = undefined;
someMethod() {
if (this.ref) {
this.ref.nativeElement;
}
}
// After
readonly ref = contentChild<ElementRef>('someRef');
someMethod() {
const refValue = this.ref();
if (refValue) {
refValue.nativeElement;
}
}
}
Configuration Options
--path
:Limits the migration to a specific sub-directory.
By default, it updates the entire Angular CLI workspace.
--analysis-dir
:Limits the analysis to a specific directory in large projects.
Useful for reducing the number of files analyzed.
Note: references outside this directory will be silently skipped, potentially breaking the build.
16. New 'strictStandalone' Compiler Flag (#57935)
Angular has introduced a new compiler flag called strictStandalone
to enforce the use of standalone components, directives, and pipes.
strictStandalone
is added to the angularCompilerOptions
. The default value is false
. When set to true
, it requires all declarations (components, directives, pipes) to be standalone.
Error Messages
When a non-standalone declaration is encountered with strictStandalone: true
:
For components: "Only standalone components are allowed when 'strictStandalone' is enabled."
For directives: "Only standalone directives are allowed when 'strictStandalone' is enabled."
For pipes: "Only standalone pipes are allowed when 'strictStandalone' is enabled."
How to use it
In tsconfig.ts you can enable it in this way:
{
"angularCompilerOptions": {
"strictStandalone": true
}
}
17. Angular directives, components and pipes are now standalone by default. (#58169)(#58229)
Specify standalone: false
for declarations that are currently declared in @NgModule
s. ng update
for v19 will take care of this automatically.
18. Promote outputFromObservable
& outputToObservable
to stable (#58214)
19. Promote takeUntilDestroyed
to stable (#58200)
20. Angular's HMR Implementation (#58205)
Angular's Hot Module Replacement (HMR) implementation involves several significant changes across the framework to enable dynamic component updates without full page reloads. This guide explains the key architectural changes and their implications.
Here is a cool post about how to play with HMR by Matthieu Riegler.
For styles is enabled by default, but if you want to do it for templates just use:
NG_HMR_TEMPLATES=1 ng serve
To run without HMR:
ng serve --no-hmr
21. Add support for the typeof
keyword in template expressions (#58183)
Adds the support for typeof
in template expressions like interpolations, bindings, control flow blocks etc.
@Component({
standalone: true,
template: `
@if (typeof value === 'string') {
{{value.length}}
} @else {
{{value}}
}
`,
})
The Angular team is working on the other features!
22. Combined migration for all signals APIs (#58259)
Adds a combined @angular/core:signals
migration that combines all of the signals-related migrations into one for the apps that want to do it all in one go.
All of the heavy-lifting was already done by the individual migrations, these changes only chain them together for a more convenient developer experience.
It includes the following migrations:
The primary use case for this migration is to offer developers interested in switching to signals a single entrypoint from which they can do so.How to run this migration?
The migration can be run using the following command:
ng generate @angular/core:signals
23. Ability to clear a FormRecord (#50750)
FormRecord is a collection of FormControls in Angular, is similar to FormGroup except it can be used with dynamic keys, with controls added and removed as needed.
In v19 it added a new feature to clear all controls from this record with some options:
emitEvent
: When true or not supplied (the default), both thestatusChanges
andvalueChanges
observables emit events with the latest status and value when the controls are removed. When false, no events are emitted.
myFormRecord = new FormRecord({one: c1, two: c2});
// This will remove all controls, and myFormRecord will be {}
myFormRecord.clear();
// If you have subscribed to it, it will emit once
// So you will see 'change' just once in console
myFormRecord.statusChanges.subscribe(() => console.log('change!'));
myFormRecord.clear();
// Won't emit if 'emitEvent' is false
myFormRecord.valueChanges.subscribe(() => console.log('change!'));
myFormRecord.statusChanges.subscribe(() => console.log('change!'));
myFormRecord.clear({emitEvent: false});
24. New rxjs-interop operator: pendingUntilEvent (#56533)
Operator which makes the application unstable until the observable emits, complets, errors, or is unsubscribed.
Use this operator in observables whose subscriptions are important for rendering and should be included in SSR serialization.
Note that it’s experimental.
// This should not block stability until subscription
const originalSource = new BehaviorSubject(0);
const delayedSource = originalSource.pipe(
delay(5),
pendingUntilEvent(injector)
);
25. Provider functions for INITIALIZER tokens (#53152)
Add a helper provider functions to simplify the use of INITIALIZER intializer tokens
provideAppInitializer()
forAPP_INITIALIZER
provideEnvironementInitializer()
forENVIRONMENT_INITIALIZER
providePlatformInitializer()
forPLATFORM_INITIALIZER
This removes the boilerplate code for the initializers like:
{
provide: APP_INITIALIZER,
multi: true,
useValue: initializerFn
}
26. Resource API / rxResource (#58255)(#58255)
Implement a new experimental API, called resource(). Resources are asynchronous dependencies that are managed and delivered through the signal graph. Resources are defined by their reactive request function and their asynchronous loader, which retrieves the value of the resource for a given request value. For example, a "current user" resource may retrieve data for the current user, where the request function derives the API call to make from a signal of the current user id.
Resources are represented by the Resource<T>
type, which includes signals for the resource's current value as well as its state. WritableResource<T>
extends that type to allow for local mutations of the resource through its value
signal (which is therefore two-way bindable).
Also, implementations of an rxjs-interop APIs which produce Resource
s from RxJS Observables. rxResource()
is a flavor of resource()
which uses a projection to an Observable
as its loader (like switchMap
).
27. New reactive primitive: linkedSignal (#58189)
A linkedSignal represents state (hence the signal in the name) that is reset based on the provided computation. Conceptually it is a state that is maintained / valid only in the context of another source signal (context is deteremined by a computation).
28. Add incremental hydration (@developer preview) (#58249)
Angular's Incremental Hydration is an experimental feature coming in Angular v19 that brings significant improvements to how applications handle hydration after server-side rendering
.
The feature introduces withIncrementalHydration()
, which can be enabled in your application configuration:
export const appConfig: ApplicationConfig = {
providers: [
provideClientHydration(
withEventReplay(),
withIncrementalHydration()
)
]
};
What makes this feature interesting is how it allows fine-grained control over component hydration using three main approaches:
hydrate on
- Uses triggers like viewport, hover, or idlehydrate when
- Activates based on boolean conditionshydrate never
- Renders content without hydrating it
This is particularly powerful because it lets developers optimize their applications by only hydrating components when they're actually needed, rather than hydrating everything at once during initial load.
For instance, a component far down the page could use:
@defer (on viewport; hydrate on hover) {
<app-heavy-component />
}
The component would be server-rendered, but only become interactive when the user hovers over it after it enters the viewport.
This PR represents a significant step forward for Angular's SSR capabilities, as it allows for more efficient resource usage and better performance, especially for larger applications. It's worth noting this is still marked as experimental in the PR, so its API might evolve before final release.
RFC: Incremental Hydration
Good article about it from Manfred Steyer: Complete Guide for Server-Side Rendering (SSR) in Angular
29. Disable keyvalue (pipe) sorting using null compareFn (#57487)
The key changes in Angular 19's KeyValue pipe are:
New Natural Order Option:
You can now pass
null
as the compareFn to preserve the natural order of keysThis eliminates the need to write a custom comparison function just to maintain original order
Backward Compatibility:
The default behavior (without parameters) still sorts alphabetically
Existing code will continue to work as before
Usage Patterns:
// Default (sorted alphabetically)
*ngFor="let item of object | keyvalue"
// Natural order (new in Angular 19)
*ngFor="let item of object | keyvalue: null"
// Custom sorting (still supported)
*ngFor="let item of object | keyvalue: myCustomSort"
This change addresses a long-standing issue where developers often wanted to preserve the original order of keys but had to write custom comparison functions to achieve this. The new null
comparator option provides a clean, declarative way to achieve this common use case.
// Component showcasing different KeyValue pipe sorting behaviors
import { Component } from '@angular/core';
@Component({
selector: 'app-keyvalue-demo',
template: `
<h3>1. Default Behavior (Alphabetical Sorting)</h3>
<div *ngFor="let item of numberedObject | keyvalue">
{{item.key}}: {{item.value}}
</div>
<h3>2. Natural Order (No Sorting) using null</h3>
<div *ngFor="let item of numberedObject | keyvalue: null">
{{item.key}}: {{item.value}}
</div>
<h3>3. Custom Sorting (Numeric)</h3>
<div *ngFor="let item of numberedObject | keyvalue: numericSort">
{{item.key}}: {{item.value}}
</div>
<h3>4. Map Example with Natural Order</h3>
<div *ngFor="let item of mapExample | keyvalue: null">
{{item.key}}: {{item.value}}
</div>
`
})
export class KeyValueDemoComponent {
// Object with numbered keys (will demonstrate the sorting difference)
numberedObject = {
'2': 'Two',
'1': 'One',
'10': 'Ten',
'20': 'Twenty',
'3': 'Three'
};
// Map example (preserves insertion order when using null comparator)
mapExample = new Map<string, string>([
['2', 'Second'],
['1', 'First'],
['10', 'Tenth'],
['20', 'Twentieth'],
['3', 'Third']
]);
// Custom numeric sort function
numericSort(a: any, b: any) {
return Number(a.key) - Number(b.key);
}
}
// Example outputs:
// 1. Default (Alphabetical):
// 1: One
// 10: Ten
// 2: Two
// 20: Twenty
// 3: Three
// 2. Natural Order (null):
// 2: Two
// 1: One
// 10: Ten
// 20: Twenty
// 3: Three
// 3. Custom Numeric Sort:
// 1: One
// 2: Two
// 3: Three
// 10: Ten
// 20: Twenty
30. Enhanced Signal Debugging Features (#57073)(#57074)
Angular DevTools is working on developing signal debugging support. This is a step in the direction of making available debug information to the framework that will allow Angular DevTools to provide users with more accurate information regarding the usage of signals in their applications.
Learn more about Signal Debugging Feature in this post.
31. Angular Material's New Timepicker Component
Angular Material is introducing a new addition to its component library: the Timepicker. This long-awaited component provides a user-friendly way to handle time selection in Angular applications, with a focus on simplicity and accessibility.
Here's a simple example of how to use the new timepicker:
<mat-form-field>
<mat-label>Pick a time</mat-label>
<input matInput [matTimepicker]="picker">
<mat-timepicker #picker/>
<mat-timepicker-toggle [for]="picker" matSuffix/>
</mat-form-field>
The timepicker can be customized through various inputs:
interval
: Set time intervals (e.g., "15m", "1h")min
/max
: Define allowed time rangesoptions
: Provide custom time optionsGlobal configuration through
MAT_TIMEPICKER_CONFIG
Check the PR for more information.
They also added a 2D feature for the actual drag & drop component and reordering of the tabs component.
32. Hash-based Strict Content Security Policy
Each script from your index.html
will have a hash added to the CSP. This adds more security and prevent attackers from introducing malicious code. This is in developer preview for now.
For more info check the schema.
33. Custom theme with Material 3
This new API reduces duplication of code using just a single mixin
:
@use '@angular/material' as mat;
html {
@include mat.theme((
color: (
primary: mat.$violet-palette,
tertiary: mat.$orange-palette,
theme-type: light
),
typography: Roboto,
density: 0
));
}
You can also use the new API to style individual components:
@include mat.sidenav-overrides(
(
'content-background-color': purple,
'container-divider-color': orange,
)
);
Now in the angular material website each componente has a new tab called Styling to show you how you can do it:
34. Pass environment variables during build time
You can use the —define
flag in you command to do it:
ng build --define "apiKey='$API_KEY'"
declare global {
var apiKey: string;
}
await fetch(`/api/data?apiKey=${globalThis.apiKey}`);
Examples from Minko post.
35. Optimization for components with empty styles (angular.love post)
Angular 19 improves how components with empty styles are handled. When a component’s styles or CSS files are empty, Angular sets encapsulation to None, preventing unnecessary attributes like “_ngcontent-ng-c885857805” from being added to HTML elements.
This update benefits projects using utility-first CSS frameworks like Tailwind CSS, where unused CSS files were sometimes not removed.
🎯 Key Benefits:
- Less runtime overhead work for scoping styles
- Lighter HTML documents in SSR response because of fewer attributes
- Applies to styleUrl, styleUrls and styles
⚠️ Note: This optimization is applied only in production builds.
Learn more about Signals
If you want to learn more about Angular Signals and to have a full overview about them, I wrote a full guide with videos included about how to use them, and at the end of the post you have a cheatsheet to bring with you in your daily reads.
And I leave you this link to the full course about Signals.
Summary of Package Updates (Angular 19)
router
Add
routerOutletData
input toRouterOutlet
directive (#57051)
core
support TypeScript 5.6 (#57424)
introduce
afterRenderEffect
(#57549)Add a schematics to migrate to
standalone: false
. (#57643)mark input, output and model APIs as stable (#57804)
stabilize
@let
syntax (#57813)change effect() execution timing & no-op
allowSignalWrites
(#57874)mark signal-based query APIs as stable (#57921)
migrate ExperimentalPendingTasks to PendingTasks (#57533)
promote
outputFromObservable
&outputToObservable
to stable. (#58214)Promote
takeUntilDestroyed
to stable. (#58200)flipping the default value for
standalone
totrue
(#58169)treat directives, pipes, components as by default (#58229)
Add rxjs operator prevent app stability until an event (#56533)
add syntactic sugar for initializers (#53152)
experimental
resource()
API for async dependencies (#58255)experimental impl of
rxResource()
(#58255)introduce debugName optional arg to framework signal functions (#57073)
introduce the reactive linkedSignal (#58189)
Add incremental hydration public api (#58249)
compiler
compiler-cli
common
language-service
add code fix for unused standalone imports (#57605)
add code reactoring action to migrate
@Input
to signal-input (#57214)allow code refactorings to compute edits asynchronously (#57214)
support migrating full classes to signal inputs in VSCode (#57975)
support converting to signal queries in VSCode extension (#58106)
support migrating full classes to signal queries (#58263)
migrations
forms
add ability to clear a FormRecord (#50750)
Thanks for reading so far 🙏
I’d like to have your feedback so please leave a comment, clap or follow. 👏
Spread the Angular love! 💜
If you really liked it, share it among your community, tech bros and whoever you want! 🚀👥
Don't forget to follow me and stay updated: 📱
Thanks for being part of this Angular journey! 👋😁