The Ultimate Guide To Angular Evolution Angular 19
The Ultimate Guide To Angular Evolution Angular 19
The Ultimate
Guide to Angular
Evolution
How Each Angular Version Impacts Efficiency,
DX, UX and App Performance
Table of Contents
Preface������������������������������������������������������������������������������������������������������������������������������������������ 5
Introduction��������������������������������������������������������������������������������������������������������������������������������� 6
How this book is organized������������������������������������������������������������������������������������������������������������������������������������������������������������ 7
Help us improve this ebook�����������������������������������������������������������������������������������������������������������������������������������������������������������9
Spread the word���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������9
Join Angular community and level up your skills���������������������������������������������������������������������������������������������������������������9
Angular v14��������������������������������������������������������������������������������������������������������������������������������� 10
Standalone API (developer preview)��������������������������������������������������������������������������������������������������������������������������������������� 11
Typed forms���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 15
Inject function�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������17
CDK Dialog and Menu�������������������������������������������������������������������������������������������������������������������������������������������������������������������� 19
Setting the page title��������������������������������������������������������������������������������������������������������������������������������������������������������������������� 20
ENVIRONMENT_INITIALIZER Injection Token���������������������������������������������������������������������������������������������������������������������������22
Binding to protected component members����������������������������������������������������������������������������������������������������������������������� 24
Angular extended diagnostics�������������������������������������������������������������������������������������������������������������������������������������������������� 25
ESM Application Build (experimental)������������������������������������������������������������������������������������������������������������������������������������27
Typescript/Node.js support���������������������������������������������������������������������������������������������������������������������������������������������������������27
Angular v15�������������������������������������������������������������������������������������������������������������������������������� 32
Standalone API (Stable)�������������������������������������������������������������������������������������������������������������������������������������������������������������� 33
Directive composition API������������������������������������������������������������������������������������������������������������������������������������������������������������ 39
Image directive��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 41
MDC-based components������������������������������������������������������������������������������������������������������������������������������������������������������������ 42
CDK Listbox����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 43
Improved stack traces������������������������������������������������������������������������������������������������������������������������������������������������������������������ 44
Auto-imports in language service������������������������������������������������������������������������������������������������������������������������������������������ 46
Typescript/Node.js support�������������������������������������������������������������������������������������������������������������������������������������������������������� 47
Angular v16�������������������������������������������������������������������������������������������������������������������������������� 50
Signals library (developer preview)���������������������������������������������������������������������������������������������������������������������������������������� 51
SSR Hydration (developer preview)���������������������������������������������������������������������������������������������������������������������������������������� 54
Vite-powered dev server������������������������������������������������������������������������������������������������������������������������������������������������������������� 56
Required inputs�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 57
Input transform function�������������������������������������������������������������������������������������������������������������������������������������������������������������� 60
Router data input bindings���������������������������������������������������������������������������������������������������������������������������������������������������������� 61
Injectable DestroyRef and takeUntilDestroyed������������������������������������������������������������������������������������������������������������������ 63
Self-closing tags����������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 65
runInInjectionContext�������������������������������������������������������������������������������������������������������������������������������������������������������������������� 66
Standalone API CLI support�������������������������������������������������������������������������������������������������������������������������������������������������������� 67
Typescript/Node.js support�������������������������������������������������������������������������������������������������������������������������������������������������������� 67
Angular v17����������������������������������������������������������������������������������������������������������������������������������73
Signals library (stable)������������������������������������������������������������������������������������������������������������������������������������������������������������������74
Signal inputs���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������76
New control flow (Developer preview)�����������������������������������������������������������������������������������������������������������������������������������78
Deferred loading (developer preview)������������������������������������������������������������������������������������������������������������������������������������81
Inputs Binding with NgComponentOutlet ��������������������������������������������������������������������������������������������������������������������������� 85
Animation lazy loading���������������������������������������������������������������������������������������������������������������������������������������������������������������� 86
View Transitions ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ 88
Esbuild + Vite (stable)������������������������������������������������������������������������������������������������������������������������������������������������������������������ 90
SSR Hydration (stable)�������������������������������������������������������������������������������������������������������������������������������������������������������������������91
CLI improvements����������������������������������������������������������������������������������������������������������������������������������������������������������������������������92
Devtools Dependency Graph������������������������������������������������������������������������������������������������������������������������������������������������������93
Rebranding and introduction of angular.dev�������������������������������������������������������������������������������������������������������������������� 94
Typescript/Node.js support�������������������������������������������������������������������������������������������������������������������������������������������������������� 95
Angular v18���������������������������������������������������������������������������������������������������������������������������������99
Hybrid Change Detection�����������������������������������������������������������������������������������������������������������������������������������������������������������100
Signal inputs������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 103
Model inputs�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������105
Signal queries���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 107
Output syntax���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 109
Collaboration Between Angular and Wiz������������������������������������������������������������������������������������������������������������������������������ 111
Ng-content fallback����������������������������������������������������������������������������������������������������������������������������������������������������������������������� 113
Route Redirects as Functions���������������������������������������������������������������������������������������������������������������������������������������������������� 114
New RedirectCommand��������������������������������������������������������������������������������������������������������������������������������������������������������������� 116
Improved Hydration Debugging Experience����������������������������������������������������������������������������������������������������������������������� 117
New Observables in Forms��������������������������������������������������������������������������������������������������������������������������������������������������������� 119
New Documentation��������������������������������������������������������������������������������������������������������������������������������������������������������������������� 120
Hydration Support in CDK and Material������������������������������������������������������������������������������������������������������������������������������� 122
Material 3������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 123
Typescript/Node.js support������������������������������������������������������������������������������������������������������������������������������������������������������� 124
Angular v19������������������������������������������������������������������������������������������������������������������������������� 132
New reactive primitive - linkedSignal (experimental)������������������������������������������������������������������������������������������������� 133
Resource API (experimental)���������������������������������������������������������������������������������������������������������������������������������������������������� 136
AfterRenderEffect Function (experimental)�����������������������������������������������������������������������������������������������������������������������140
Minor signal improvements������������������������������������������������������������������������������������������������������������������������������������������������������� 141
@let template variable syntax������������������������������������������������������������������������������������������������������������������������������������������������� 143
Incremental Hydration (experimental)��������������������������������������������������������������������������������������������������������������������������������144
Server Route Configuration (experimental)���������������������������������������������������������������������������������������������������������������������� 147
RouterOutlet data input��������������������������������������������������������������������������������������������������������������������������������������������������������������148
RouterLink directive enhancements��������������������������������������������������������������������������������������������������������������������������������������150
Default query params handling strategy���������������������������������������������������������������������������������������������������������������������������� 151
Components become standalone by default������������������������������������������������������������������������������������������������������������������ 152
New useful migrations (injections, standalone API)������������������������������������������������������������������������������������������������������ 153
Strict standalone flag������������������������������������������������������������������������������������������������������������������������������������������������������������������� 155
Initializer provider functions������������������������������������������������������������������������������������������������������������������������������������������������������156
New angular diagnostics������������������������������������������������������������������������������������������������������������������������������������������������������������ 158
Hot module replacement for ng serve��������������������������������������������������������������������������������������������������������������������������������� 159
New features in Angular Language Service�����������������������������������������������������������������������������������������������������������������������160
Typescript/Node.js support������������������������������������������������������������������������������������������������������������������������������������������������������� 162
The future���������������������������������������������������������������������������������������������������������������������������������� 164
Signal Forms�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������164
Selectorless���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������166
Zoneless Angular����������������������������������������������������������������������������������������������������������������������������������������������������������������������������166
Streamed server-side rendering��������������������������������������������������������������������������������������������������������������������������������������������166
Overall������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 167
What the experts are saying ������������������������������������������������������������������������������������������������ 168
How important is it to stay up-to-date with all the latest changes in Angular, given the current pace
of changes?��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������168
How do the overall changes affect the learning curve? Is it easier to learn Angular in its latest form? ������� 171
What are your expectations for the direction and pace of change in Angular in the future?��������������� 173
What is your most anticipated feature in the Angular Roadmap?������������������������������������������������������������������������� 174
Thank You��������������������������������������������������������������������������������������������������������������������������������� 175
Consulting and audit�������������������������������������������������������������������������������������������������������������� 176
Media partners���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������177
Bibliography����������������������������������������������������������������������������������������������������������������������������� 178
About authors�������������������������������������������������������������������������������������������������������������������������� 178
Main Authors������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ 178
Special thanks to���������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 178
Invited experts��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 179
Preface
This ebook is a combination of Angular roadmap and changelog, supplemented with
clear explanations and use cases of all relevant changes in recent years. It brings
together all the new features in one place and puts them in a broader context of
Angular’s evolution. Regardless of whether you are interested in learning about
a specific functionality or want to stay up to date with all the changes and their impact
on the framework, this text has got you covered.
Regularly updating the Angular version will make your application easier to maintain
thanks to features and tools that make it easier to develop, test, and improve your
application. This translates directly into several benefits for your business, including
improved app performance, better security, increased developer efficiency, and better
user experience.
This ebook will serve as your guide to previous Angular versions, the changes and new
features they brought. As a bonus it provides expert insights and predictions of what
the framework will look like in the future.
We will be focusing on versions 14 and up. This is because the earlier period of Angular
development was marked by significant internal changes (related to the migration of
the compiler and rendering engine to Ivy), which, at the same time, meant much less
new functionality and changes to the framework’s API. To visualize this, we can try to
divide the lifespan of Angular so far into three phases:
Angular along with other frameworks like React and Vue, popularized sin-
gle-page applications and built a strong community around them. The first
versions of Angular were very thoroughly battle-tested. During that period the
limitations of the legacy build and rendering pipeline called “View Engine” were
learned. After that Angular core developers decided to completely redesign it
and gave it a new code name called “Ivy”. Complete migration took a few years
to finally abandon the previous solution.
Ivy engine introduced a number of new opportunities and brought us into the 3rd
Phase, a kind of “boom” of new functionalities and long-term shifts in Angular mental
models. In the following pages, we will look at all of these in detail.
Our approach to presenting this content is systematic and reader-friendly, ensuring that
you can both grasp the technicalities and see the broader picture of each feature’s
impact. We structured all functionalities into three distinct sections:
Challenge - This section outlines the specific problem or need that the new feature
addresses. Understanding the challenge provides context and highlights the
significance of the feature in real-world scenarios.
Solution - Here, we delve into the technical details of the feature. We describe how it
works, its implementation, and any variations or configurations that are relevant.
Benefits - This part showcases the advantages of using the feature. We focus on how it
contributes to business values.
To further enhance your reading and learning experience, each feature is categorized
using labels. That way, you have the option of reading this ebook cover-to-cover to get
a full picture of Angular’s evolution or jump to specific sections that are most relevant to
your immediate needs. The labels and structured format make it easy to find and focus
on the features that are most pertinent to your current projects or interests.
You, as a reader, would know much better how to make the Guide more useful,
so it really serves your needs and solves your problems.
We’ve created this ebook because we believe that Angular has a great potential
and using the latest versions can boost efficiency, developer experience and per-
formance of your applications.
Share the information about the ebook via Twitter, LinkedIn, Facebook or Reddit.
Partner conferences:
WeAreDevelopers https://www.wearedevelopers.com/world-congress/
WAYS CONF https://www.waysconf.com/
Standalone API
Angular v14
release date: 06.2022
Before version 14, a significant goal was accomplished with the final deprecation of the
legacy View Engine. This change, along with aligning all internal tools with Ivy, not only
simplified but often enabled the introduction of innovations in Angular. It also led to
easier framework maintenance, reduced codebase complexity, and smaller bundle
sizes.
This was the first wave of improvements made possible by Ivy. The best examples are the
Standalone API (in developer preview), Typed Forms and better developer experience
related to debugging applications, both in the CLI and in the browser.
Challenge:
Although ECMAScript has a native module system supported in all modern browsers,
Angular delivers its own module system, which is based on NgModules.
NgModule is a structure that describes how to create an injector and how to compile
a component’s template at runtime. It includes definitions of components, directives,
pipes, and service providers that will be added to the application dependency injectors.
The goals of NgModules are to organize the application and extend it with capabilities
from external libraries.
This solution was met with some criticism from the beginning, because it was considered
too complicated and illegible. The complex connections between modules and their
providers, unclear dependencies between components, and unclear NullInjectorErrors
were some of the reasons a simplified alternative needed to be provided.
Solution:
In version 14 (developer preview), the Angular Team made NgModules optional with
full backward compatibility. Creating components, directives and pipes as standalone
is possible by setting the “standalone” flag to true in their decorators.
//in module
@NgModule({
imports: [FooterComponent],
})
export class Module {}
//in component
@Component({
selector: main,
template: ‘<ng-content></ng-content>’,
standalone: true,
imports: [FooterComponent ]
})
export class Component {}
//routing
export const ADMIN_ROUTES: Route[] = [
{path: ‘footer’, component: FooterComponent}
];
@Component({
selector: ‘my-app’,
standalone: true,
template: ‘<h1>Hi there!</h1>’,
})
export class AppComponent {}
bootstrapComponent(AppComponent);
How does it affect the routing? The new API allows to lazy load standalone paths
directly, with no need for NgModule:
RouterModule.forRoot([
{
path: ‘/path/to/standalone/component’,
loadComponent: () => import(‘./default-standalone.cmp’)
}
]);
There is also no need for NgModule while testing standalone components. This is how
the test case can look like
At this point, in developer preview mode, the change is not production-ready. It has some
problems to overcome. (Spoiler: Angular overcomes them in Angular version 15). Still, it
presents a major mental model change that turns standalone components into basic
building blocks of an application.
Benefits:
This revolution boosts the developer experience by:
• reducing boilerplate,
• making reading component code (especially dependencies) easier,
• removing the whole concept of an extra module system based on NgModules,
• improving compilation time, and
• lowering the entry barrier for novice developers.
Reduced bundle size and Tree-Shaking (thanks to function-based API) also improves
the performance. More details and benefits are described in chapter “Angular 15”, where
Standalone API becomes Stable.
Expert Opinion:
Standalone APIs will make the authoring and building of Angular apps much
simpler, especially for beginners to the Angular framework. The concept of Angular
modules had been complex to explain and many developers who wanted to learn
Angular were confused. Thankfully Standalone APIs will change that.
~ Aristeidis Bampakos
Google Developer Expert
From my perspective, the introduction of the Standalone API has significantly simplified
the learning curve for Angular. In the past, learners had to grapple with understanding
the complex NgModule relationships, including figuring out what to export, where to
import, and dealing with the intricacies of eager and lazy-loaded routing. Standalone API,
however, empowers developers to concentrate solely on the component they are
working on, without the need to concern themselves with the intricacies of the NgModule.
The extension of this approach to Pipes and Directives is like the icing on the cake.
Furthermore, Angular CLI provides support for creating projects with a focus on the
standalone component-based approach, which is a valuable feature. There are also
several open-source libraries available to facilitate the migration of applications from
NgModule-based architecture to a standalone component-based one, making
this transition smoother and more accessible.
~ Balram Chavan
Google Developer Expert
~ Marko Stanimirović
Google Developer Expert
Dev Experience
Challenge:
Before Angular version 14, many APIs related to Reactive Forms (FormGroup,
FormControl, FormArray, etc.) included the usage of “any” type. This resulted in poor
type safety, bad support for coding tools, codebase inconsistency and problematic
refactoring.
Solution:
In response to the challenges mentioned above, the Angular Team introduced Typed
Forms. Existing reactive forms were extended to include generic types to enforce type
safety for form controls, groups, and arrays. By applying types, you can catch potential
errors at compile time, making your codebase more robust and maintainable.
The reason control values are nullable is because of the control.reset() method. If you
don’t pass an argument, it will change the value to null. However, it’s possible to change
this behavior by setting the new flag called ‘nonNullable’:
nameFormControl.reset();
// reset method will change value to empty string
Things get more interesting when we inspect the behavior of complex controls, like
FormGroup:
The possibly undefined type comes from the fact that name control might be
disabled (and not included in form value object).
For the use cases where we don’t know all control keys beforehand, like when controls are
added dynamically, the Angular Team added the new FormRecord class.
Migrating to Angular 14 will not break any existing untyped forms, because all
occurrences of forms classes will be automatically replaced by their untyped versions:
You can incrementally migrate to Typed Forms by removing the “Untyped” prefix
in your application.
Benefits:
Leveraging TypedForms in Angular:
• Leads to more readable, maintainable, and reliable code: this feature
enhances type safety and development efficiency by providing compile-time checking
and improved IDE support for autocompletion and error detection. Discrepancies in
data types or structures are caught early, and refactoring becomes safer and more
straightforward.
Inject function
Challenge:
So far, when it comes to dependency injection, we have been limited to injections through
the constructor. This brings some limitations associated with reusability (as we could
not reuse the constructor definition), testing, and a general separation of concerns. For
example, classes required a knowledge of how to create their dependencies instead of
focusing purely on their main responsibilities.
Solution:
The ‘inject’ utility function allows us to retrieve an instance of dependency from the
Angular Dependency Injection System outside of a class constructor. This function
has to be called in an injection context, that is one of the following:
• a constructor of the component, directive, pipe, injectable service or NgModule,
• an initializer for fields of such classes,
• a factory function (in a ‘useFactory’ object of a provider or an injectable),
• an InjectionToken’s factory, or
• a function within a stack frame that is run in an injection context.
Let’s take a look at an example of usages inside a component:
@Component({...})
class HomeComponent {
private readonly dependencyA: DependencyA;
private readonly dependencyB: DependencyB = inject(DependencyB);
constructor() {
this.dependencyA = inject(DependencyA);
}
}
When you want to verify if you’re in an injection context, you can use a helper function
called assertInInjectionContext:
This feature allows us to create many reusable DI-dependent functions like the following:
@Component({...})
class ProductDetails {
private readonly productId$ = getProductId();
...
}
Benefits:
The inject function in Angular:
• Provides flexibility: allows developers to access service instances and other
dependencies outside of class constructors, making code more modular and testable.
• Streamlines the process of dependency retrieval: promotes cleaner and more
maintainable code by abstracting the complexity of dependency management and
injection.
Challenge:
Before the introduction of the CDK, styling certain components available in Angular
Material was difficult due to their ready-made design.In such a situation, it was
necessary to overwrite the styles of a given component, which could be problematic.
Solution:
Thanks to the CDK, it is possible to create unstyled dialogs and menus and customize
them by ourselves.
<ng-template #menu>
<div cdkMenu>
<button cdkMenuItem>Item 1</button>
<button cdkMenuItem>Item 2</button>
<button cdkMenuItem>Item 3</button>
</div>
</ng-template>
Challenge:
Angular provides a Title service that allows modifying the title of a current HTML document.
To use it, you have to inject it. It is completely independent from routing, so any linking to
the data in the routing configuration requires complex logic using Angular Router.
Solution:
Angular 14 offers a new feature - TitleStrategy - to set unique page titles using the new
Route.title property in the Angular Router. The title property takes over the title of the
page after routing navigation.
It is also possible to provide a custom TitleStrategy to apply more complex logic behind
a page title.
@Injectable()
@NgModule({
…
providers: [{provide: TitleStrategy, useClass: TemplatePageTitleStrategy}]
})
export class MainModule {}
Benefits:
This feature is:
• A new convenient way for manipulating a page title: with no dependency injection
and reactivity overhead.
Challenge:
It was possible to use a class with NgModule decorator to run initialization logic, i.e.:
@NgModule(...)
export class LazyModule {
constructor(configService: ConfigService) {
configService.init();
}
}
But in the absence of NgModules, some Standalone API counterpart was needed.
Solution:
The Environment injector is a more generalized version of the module injector, intro-
duced together with Standalone APIs in Angular v14. ENVIRONMENT_INITIALIZER is a to-
ken for initialization functions that will run during the construction time of an envi-
ronment injector.
When we navigate to a lazy loaded route, a new environment injector is also creat-
ed for that route. Then we can provide ENVIRONMENT_INITIALIZER functions that will
be executed upon such navigation. Inside the initialization function, you can use
the inject(...) function and perform any logic you need when the application is boot-
strapped or lazy loaded content is instantiated.
bootstrapApplication(AppComponent, {
providers: [
{
provide: ENVIRONMENT_INITIALIZER,
multi: true,
useValue: () => inject(ConfigurationService).init(),
},
],
});
Benefits:
This Injection token:
• Increases efficiency: we can place our initialization logic for the entire appli-
cation or a specific lazily loaded route in a way that is compatible with Stan-
dalone APIs and NgModules.
• Improves developer experience: this part of the process is now more clear
and convenient to carry out.
Dev Experience
Challenge:
Only public members of a component were accessible in its component template.
It meant that every binding in the template was also a part of the component’s pub-
lic API. Component classes exposed too much and violated encapsulation.
Solution:
In Angular v14, it is possible to use fields marked as protected in the template.
@Component({
selector: 'my-component',
template: '{{ message }}', // Now compiles!
})
export class MyComponent {
protected message: string = 'Hello world';
}
Benefits:
With this change, we get:
• An improved developer experience: the overall encapsulation is improved.
We can now encapsulate (hide) methods and properties that we use inside
a component’s template but don’t want to expose them anywhere else.
Challenge:
Sometimes in the Angular codebase, there are potential anomalies that are not
straightforward bugs. For example, when they don’t cause a compilation error and
meet all syntax requirements. At the same time, objections might occur, and they
might not necessarily reflect what the programmer had in mind.
<component ([foo])=”bar”></component>
This is a valid Angular example, but it is not a standard two-way data binding. Instead,
it is a one-way data binding for an event (output) called “[foo]”. The valid two-way data
binding looks like this:
<component [(foo)]=”bar”></component>
Solution:
Angular 13.2.0 brought us a new functionality called Extended Diagnostics. It’s a tool
built into the compilation process of Angular view templates (it’s part of the compiler
itself), and it doesn’t require any additional infrastructure or scripts. – It simply works
out of the box, and with the ng serve during the transpilation process.
Its task is to detect potential anomalies just like the one mentioned above. It serves
as a kind of additional linter for angular view template syntax. We enable it inside
the tsconfig file in the angularCompilerOptions section.
Ideas for new diagnostics can be submitted via the github feature requests:
https://github.com/angular/angular/issues/new?template=2-feature-request.yaml
Benefits:
These extended diagnostics result in:
• Improved code security and reliability: with no extra effort and/or cost.
Challenge:
The standard Angular bundler is considered quite slow by developers. The Angular Team
tested various other approaches that can speed up the package-building process.
Solution:
Angular version 14 introduces an experimental feature that leverages the esbuild-based
build system for the “ng build” command. This experimental build system compiles pure
ECMAScript Modules (ESM) output.
To enable it, use the following snippet in the angular.json config file:
“builder”: “@angular-devkit/build-angular:browser-esbuild”
Esbuild itself is an extremely fast JavaScript bundler and minifier written in the Go
language that’s designed for modern web development. It supports heavy par-
allel processing and might significantly outperform competitors such as Webpack.
Its support in Angular framework will be developed in the upcoming releases.
Benefits:
Introducing a new esbuild-based build system is:
• A step towards faster build-time performance: including both initial builds
and incremental builds.
• An opening to new tools: thanks to ESM, which includes dynamic import
expressions for lazy module loading support.
Typescript/Node.js support
Support for Node.js v12 and Typescript older than 4.6 has been removed. Angular 14
supports TS v4.7 and targets ES2020 by default, meaning initial bundle size is reduced.
Here are the new feature examples in the now-supported Typescript:
Dev Experience
Challenge:
Developers who frequently work with Promises, especially with async/await syntax,
sometimes want to explicitly describe the type of value returned by the resolved
Promise. For regular synchronous functions, there is the ReturnType<FnType> utility, but
before TypeScript 4.5, there was no counterpart for asynchronous functions.
Solution:
A new utility type called Awaited was introduced in TypeScript 4.5. It unwraps
promise-like “thenables” without relying on PromiseLike, and it does it recursively.
// Name = string
type Name = Awaited<Promise<string>>;
// Age = number
type Age = Awaited<Promise<Promise<number>>>;
Benefits:
Extra explicit typing of async functions:
• Positively affects the type-safeness, and
• Improves code readability.
Dev Experience
Challenge:
TypeScript could not correctly use template string types to narrow the type in
discriminated unions. In such cases, the exact type could not be inferred therefore,
typing support was limited.
Benefits:
This change brings:
• More flexibility: when defining types and more intelligent type inference by TypeScript
transpiler.
Dev Experience
Challenge:
If we had a discriminated union and we tried to destructure it, we could no longer narrow
its members using discriminator property.
Solution:
Since TypeScript version 4.6, it is possible to narrow destructed discriminated object
properties. The following example explains such a case:
Benefits:
We gain more flexibility when using and mixing discriminated unions and object
destruction.
Dev Experience
Challenge:
In JavaScript classes, it’s necessary to invoke super() before using “this” keyword.
TypeScript also has this rule, although it used to be excessively strict in ensuring it. In
TypeScript, it used to be considered an error to have any code at the start of a constructor
if the class containing it had any property initializers.
Solution:
From now on we can place a code inside the constructor, before calling “super()”. Note
that it is still mandatory to call super() before referring to the “this“ keyword.
Benefits:
The unnecessary limitation has been removed and the transpiler still validates the code
correctly, giving more freedom to the programmer.
Image Directive
Standalone API
Angular v15
release date: 11.2022
Angular v15 introduces significant improvements, phasing out legacy systems,
enhancing developer experience and optimizing performance. Standalone APIs are now
stable, supporting simpler development practices and ensuring compatibility with core
libraries. The release includes more efficient bundling with tree-shakable standalone
APIs for Router and HttpClient and an ngSrc image directive for smarter data fetching
and improved performance.
Challenge:
The problems with NgModules and the benefits of the Standalone API were presented
in the Angular 14 chapter. The solution at that time had disadvantages related to not
being in a stable version, as well as shortcomings regarding providers, adapting many
basic modules and benefiting from abandoning modules.
Solution:
Starting with version 15, the standalone APIs drop the developer preview label and
become stable. Thanks to this, we get the green light to safely utilize them in our
applications, including production.
Let’s explore the major changes around Angular Routing. First, we received a new type
of guard – canMatch. So what’s the difference between this new one, canLoad, which tells
us whether we can load a route that references a lazily loaded module, and canActivate/
canActivateChild, which tells us whether we can activate a child route/route? CanMatch
works, in a sense, at a different, “earlier” stage and decides whether the current url can
be matched against a given route. This means it can play a similar role to both canLoad
(which it will eventually replace) and canActivate.* However when it returns false,
subsequent routing configuration entries are processed.
This means we gain a new possibility – defining a route with the same path, but
navigating to different places based on the logic implemented by the guard. This is
useful, for example, when handling different user roles, or conditionally loading another
version of the feature based on feature flags. Here’s a usage example:
The Router API has been fully adjusted to the standalone approach, so we no longer need
to use the Router Module. Instead, we get a whole set of alternative APIs, which also have
the advantage of being easily treeshakeable:
bootstrapApplication(AppComponent, {
providers: [
provideRouter(
routes,
withDebugTracing(),
withPreloading(PreloadAllModules)
),
],
});
A small, but lovely, improvement also appeared in the syntax for importing lazy-loaded
paths. It is possible to omit the “.then(...)” part if we use the default export in the target file.
@Component({
standalone: true,
...
})
export default class MyComponent { ... }
{
path: ‘home’,
loadComponent: () => import(‘./my-component’),
}
{
path: ‘admin’,
providers: [AdminService],
children: [
{path: ‘users’, component: AdminUsersCmp},
{path: ‘teams’, component: AdminTeamsCmp},
],
}
Providers declared in the route are available for the component declared at the same
level and for all its descendants.
Similarly to Router, HttpClient has also been adapted to the module-less approach:
bootstrapApplication(AppComponent, {
providers: [
provideHttpClient(
withXsrfConfiguration({
cookieName: ‘MY-XSRF-TOKEN’,
headerName: ‘X-MY-XSRF-TOKEN’,
})
),
],
});
bootstrapApplication(AppComponent, {
providers: [
provideHttpClient(
withInterceptors([
(request, next) => {
console.log(‘Url: ‘, request.urlWithParams);
return next(request);
},
])
),
],
During migration to functional interceptors, you can still use your class-based interceptors
configured using a multi-provider by adding withInterceptorsFromDi utility function as
follows:
bootstrapApplication(AppComponent, {
providers: [
provideHttpClient(withInterceptorsFromDi()),
{
provide: HTTP_INTERCEPTORS,
useClass: YourClassBasedHttpInterceptor,
multi: true,
},
],
});
If in your standalone app, you need any providers from third-party libraries that are
available only inside NgModules, you can use the importProvidersFrom utility function:
bootstrapApplication(AppComponent, {
providers: [importProvidersFrom(MatDialogModule)],
});
@Component({...})
export class MyComponent {
constructor(private readonly viewContainerRef: ViewContainerRef) {}
create(): void {
this.viewContainerRef.createComponent(OtherComponent);
}
}
Benefits:
The proposed module-less approach:
• Simplifies the process of application development: reduces the reliance on
NgModules and minimizes boilerplate code.
• Enables faster development cycles and a cleaner codebase: provides a more
direct and streamlined API for key aspects like bootstrapping, routing, and dynamic
component instantiation.
• Improves app performance: thanks to the shift towards a providers-first
approach, which enhances tree-shakability.
Expert Opinion:
The standalone API makes many things easier. Especially since you now have to provide
everything you need in one component, and it does not magically come from somewhere.
This makes the topic of DependencyInjection much easier to understand. This also made
the lazy loading of components possible. My tip for this: Declare the component class as
a default export so that you don’t have to resolve the promise yourself during lazy load-
ing. This makes the dynamic import shorter.
~ David Muellerchen
Google Developer Expert
Challenge:
One of the most wanted features in the framework was the ability to reuse directives
and apply their behavior to other directives or components.
Up to this point, there have been few possibilities to partially achieve a similar result,
such as the use of inheritance, where the main limitation is that only one base class
can be used.
Another idea used, for example, by Angular Material, is the use of TypeScript mixins. But
this forces a specific approach to the code shared this way, which heavily complicates
implementation and doesn’t allow for the use of Angular APIs in mixins.
Solution:
The Directive Composition API in Angular is a feature that allows directives to be
applied to a different directive or a component’s host element directly from within
the component’s TypeScript class. The only major restriction is that only standalone
directives can be applied to our directives/components, which on the other hand,
don’t need to be standalone.
@Component({
selector: ‘my-component’,
templateUrl: ‘./my-component.html’,
hostDirectives: [
{
directive: NgClass,
},
{
directive: CdkDrag,
inputs: [‘data’],
outputs: [‘moved: dragged’],
},
],
standalone: true,
})
export class MyComponent {}
But can we control the behavior of applied directives from inside the component? This is
possible using the inject function, which allows us to inject the instance of the directive
into the component and manipulate its properties. It looks like this:
@Component({
selector: ‘my-component’,
templateUrl: ‘./my-component.html’,
hostDirectives: [
{
directive: NgClass,
},
],
standalone: true,
})
export class MyComponent {
private ngClassDirective = inject(NgClass);
someCallback(): void {
this.ngClassDirective.ngClass = ‘my-class’;
}
}
Benefits:
Directive Composition API:
• Improves the developer experience: enhances code modularity by allowing
developers to encapsulate and reuse behaviors across different components and
directives.
• Leads to a cleaner and more organized codebase
• Makes the maintenance and updating of the application more efficient.
Image directive
Efficiency Performance UX
Challenge:
The app may take a long time to load in the browser due to the way images are loaded.
This can be especially noticeable when the website contains a lot of multimedia.
Solution:
In collaboration with the Aurora team, the Angular team has introduced the
NgOptimizedImage to enhance image optimization and incorporate best practices
for image loading performance. It is a standalone directive designed to boost
image loading efficiency. It became a stable feature in Angular version 15.
To activate iNgOptimizedImage, simply replace the image’s src attribute with ngSrc.
<img ngSrc=”cat.jpg”>
If the LCP image is shown, a good way to prioritize its loading is to use property called
“priority”.
Benefits:
Using the NgOptimizedImage directive and ngSrc attribute is very simple, almost
cost-free, and can significantly improve an application’s performance, SEO and core
web vitals.
MDC-based components
Challenge:
The current version of the Angular Material library was loosely linked to the official
Material Design specification. All the styles and behaviors were reinterpreted and
reimplemented to Angular style. With the arrival of Material Design Components for Web
(MDC), the library became outdated It became clear that new Angular Material should
be strongly and directly based on official MDC design tokens. These include values like
colors, fonts and measurements.
Solution:
In Angular Material version 15, a significant migration took place. Many components
are now being refactored to be based on Material Design Components for Web
(MDC). Various components have been refactored, leading to changes in styles, APIs
and even complete rewrites for some. Components like form-field, chips, slider and
list have significant changes in their APIs to integrate with MDC. There are library-wide
changes affecting component size, color, spacing, shadows and animations to improve
spec-compliance and accessibility. Theming changes include updates to default
typography levels and themeable density. Each component has specific changes,
including style updates, element structure and API modifications.
Benefits:
These changes offer several benefits, such as:
• Improved accessibility
• Better adherence to the Material Design spec
• Faster adoption of future Material Design versions: due to shared infrastructure
Challenge:
Creating a typical listbox with accessibility support, keyboard events support,
multiselection and correct scroll behavior, as well as satisfying WAI ARIA listbox pattern
requirements is a time-consuming task.
Solution:
The newly added component to the Angular CDK library meets all the above guidelines
while being a fully customizable solution.
Appointment Time
Dev Experience
Challenge:
Up until now, the stack traces presented in CLI and browser devtools were quite obscured
by external functions (i.e. from webpack or node_modules). It was hard to investigate
the execution order when the trace included many lines from outside the code written by
the programmer.
Solution:
Improvements in this area are possible thanks to the cooperation of the Angular Team
and the Chrome team. The goal was to mark scripts as “external” and thus exclude them
in the development tool functions(e.g. stack traces). Starting with Angular 14.1, the
contents of the node_modules and webpack folders are marked in this way. It is worth
mentioning that this mechanism is available to all developers, so authors of other
frameworks can use it as well.
The result is a stack trace that omits scripts that are probably not in the developer’s area
of interest when an error is shown in the console. Also, the code that belongs to excluded
scripts is skipped when you’re debugging and iterating over subsequent instructions in
the code.
Call Stack
(anonymous) app.component.ts:36
Promise.then (async)
(anonymous) app.component.ts:27
Zen - setTimeout (async)
(anonymous) app.component.ts:4
timeout app.component.ts:4
(anonymous) app.component.ts:22
Zone - Promise.then (async)
(anonymous) app.component.ts:22
increment app.component.ts:38
AppComponent_Template_app_button_handleclick_3_listener app.component.ts:12
onClick app.component.ts:18
ButtonComponent_Template_input_click_0_listener app.component.ts:1
Zone - HTMLInputElement.addEventListener:click (async)
ButtonComponent_Template app.component.ts:1
Benefits:
Both sync and async traces have readable form and provide more information to the
programmer. Therefore these improvements:
• Boost developer experience
• Ease the debugging process
Challenge:
With Standalone API, we frequently need to add extra imports to the Component
metadata, because the only components, directives and pipes available in the
template are ones we explicitly imported.
Solution:
The Angular Language Service is a tool utilized by all code editors to enhance errors, hints
and navigation between Angular templates. The new DX-related improvement,
a part of language service, allows us to automatically import components whose
selectors were used in another component’s template. This applies to both
standalone and module-based components.
@Component ({
selector: ‘app-root’,
template: ‘<app-foo></app-foo>’,
styleUrls: [‘./app Quick Fix...
}) Import FooModule from ‘./foo/foo.module’ on AppModule
export class AppComp
Extract...
title = ‘tour - of - k
Extract to readonly field in class “AppComponent”
}
Benefits:
This tool is utilized by IDEs, and it significantly simplifies and speeds up the import
of components, directives and pipes using keyboard shortcuts, enabling the
programmer to focus on other tasks.
Angular 14.2 added support for TypeSript 4.8, Node.js v18 and Angular 15.1 added
support for Typescript 4.9. According to the official documentation, it includes, among
other things, a number of performance improvements that can reduce build and hot
reload times of TypeScript projects by up to 40%. Let’s take a look at other new features
worth mentioning.
Dev Experience
Challenge:
When we define an expression, TypeScript infers the most general type for it:
In the example above, the typeof “name” property is not narrowed to const literal ”John”
but generalized to any string value. In some cases, we would like to ensure that
the expression matches a certain type while also ensuring the most specific type at the
same time.
Solution:
TypeScript version 4.9 introduced a new operator called “satisfies.” It validates whether
the type of an expression matches a type without changing the resulting type of that
expression.
This operator can be combined with “as const” to infer type from constant values and
check them against a broader type at the same time:
const friends = [
{ name: ‘John’ },
{ name: ‘Paul’ },
] as const satisfies readonly { name: string }[];
In the example above, expression is type-checked with the satisfies operator, but
the inherited type for friends const comes directly from the value.
Satisfies is somewhat similar to “as” operator. The difference is that with “as,”
the programmer is responsible for the type safety and with “satisfies”, TypeScript
validates the type we assert automatically.
Benefits:
The new operator improves the TypeScript developer experience as it enforces
type safety without the loss of information (i.e. via type widening). By replacing the
“as” operator with “satisfies,” we also reduce the reliance on untrustworthy type
assertions. The code readability is also improved in some cases.
Dev Experience
Challenge:
In IEEE-754 floats standard, supported by JavaScript and TypeScript, nothing is ever
equal to NaN, the“not a number” value. However, it is a common mistake to check it with
someValue === NaN, instead of using the built-in Number.isNaN function.
Solution:
Typescript no longer allows direct comparisons against NaN and suggests Number.is-
NaN instead:
Benefits:
Thanks to the new restriction, we avoid an obvious error and are clearly informed
about an error.
Non-destructive Hydration
Signals
Angular v16
release date: 05.2023
Angular version 16 brings substantial advancements, focusing on creating a more
modern and efficient framework. The introduction of signals marks the beginning of
a refined change detection mechanism, while non-destructive hydration sets the stage
for advanced hydration scenarios crucial for public web platforms.
Challenge:
Angular applications can face performance issues due to inefficient change detection
mechanisms, resulting in an excessive number of computations to determine what has
changed in the application state. Additionally, developers might struggle with a more
complex mental model for understanding reactivity, data flow, RxJS and dependencies
within the application, making it harder to write, maintain, and optimize their code
efficiently.
Solution:
In Angular 16, we received a developer preview of a brand new library containing
a primitive that represents a reactive value–the Angular signals library.
Angular’s signals library introduces a way to define reactive values and establish explicit
dependencies between them within an application. Unlike RxJS, observables that push
changes through a stream of values, signals allow for a more direct and straightforward
way to declare reactive state, compute derived values and handle side-effects, offering
a different approach to managing reactivity in Angular applications.
@Component({...})
export class App {
firstName = signal(‘Ash’);
lastName = signal(‘Ketchum’);
fullName = computed(() => `${this.firstName()} ${this.lastName()}`);
setName(newName: string): void {
this.firstName.set(newName);
}
}
‘firstName’ and ‘lastName’ are writable signals, meaning they provide an API for updating
their values directly. ‘fullName’ is a readonly signal that depends on the other signals and
is recalculated every time any dependent signal changes its value.
In many cases, it is useful to define a side effect. This is a call to code that changes state
outside its local context, such as sending an http request or synchronizing two
independent data models. To create an effect we can use “effect” function:
effect(() => {
console.log(`The current value of my signal is: ${mySignal()}`);
});
The Angular Team also provides a bridge between signals and RxJS, placed in the
@angular/core/rxjs-interop library. It is possible to convert a signal to observable and an
observable to a signal.
lastName$ = of(‘Ketchum’);
lastName = toSignal(this.lastName$, ‘’);
}
The real revolution will come when the Angular Team releases signal-components. These
components will work without zoneJS and will have their own change detection strategy
based solely on signals. It will be possible to update DOM elements with surgical
precision, without unnecessary traversal of the component tree.
It’s also worth mentioning that external libraries like ngrx also implement support for
signals. The NgRx store will have its signal-based counterpart called SignalStore.
Benefits:
The introduction of a new experimental reactive primitive is a promise of a simplified
mental model for reactivity in Angular. Its goals are to lower the learning curve, reduce
the number of errors and make the whole development process intuitive and
straightforward. With the future arrival of signal-based components, significant
performance improvements are expected.
I think signals will have a dramatic impact on many sides of the framework from
performance to bundle size improvements. This will be especially visible when signals are
integrated into the change detection mechanism. It will make the process much more
efficient and performant because, unlike the current zone.js-based implementation,
signals will allow Angular to know in which exact component a change occurred and
update only the affected components. Besides that, the change detection mech-
anism will become much simpler and unified, because we will have only one predictable
change detection strategy, which will also have a positive impact on the learning curve.
Finally, we will be able to reduce bundle size by removing the zone.js dependency, which
will not be needed for the new change detection mechanism. And this is just one of the
examples. I think that we are currently seeing only the tip of the iceberg.
~ Dmytro Mezhenskyi
Google Developer Expert
The Angular signal feature is currently in its Developer Preview stage. Once this feature
becomes stable, it is poised to introduce an entirely new approach to writing
Angular applications. The elimination of zone.js will free developers from concerns
related to change detection cycles and performance issues, allowing them to
concentrate more on their business logic. This is exemplified by the transition from
familiar [(ngModel)] binding syntax to the new signal and effect syntax, which requires
developers to adapt and update their projects. Despite these changes, I firmly believe
that this innovation holds great promise in advancing the framework to the next level.
~ Balram Chavan
Google Developer Expert
Performance UX
Challenge:
By default, Angular renders applications only in a browser. If any web crawler tries to
index the page, it receives an almost empty HTML file and is unable to navigate and find
searchable content. This is one of the reasons why we might want to implement
Server-Side Rendering, the process of rendering our site on the server side and returning
the whole HTML structure.
A server-side rendered HTML is displayed in the browser, while the Angular app
bootstraps in the background, reusing the information available in server-generated
HTML. The HTML then destroys DOM and replaces it with with a newly rendered and fully
interactive Angular app.
Solution:
Angular introduced hydration, a new feature currently available for developer preview.
We can enable it as follows:
bootstrapApplication(RootCmp, {
providers: [provideClientHydration()]
});
It enables reusing server-side rendered HTML in the browser without destroying it.
Angular matches the existing DOM elements with application structure at runtime. This
results in a performance improvement in Core Web Vitals and a better SEO performance.
There is also an option to skip hydration for some components, or rather component
trees, if they’re not compatible with hydration. For example, manipulating DOM directly
with browser APIs. Use one of the following options to enable hydration:
#1
#2
@Component({
...
host: {ngSkipHydration: ‘true’},
})
class TestComponent {}
If your Angular application uses SSR, you should definitely check this feature out. More
details are available in the official documentation: https://angular.io/guide/hydration
Benefits:
Full hydration brings:
• Better UX: faster loading and interactivity, no more flickering
• Enhanced SEO: in comparison to destructive hydration
Expert Opinion:
The Angular team has been deeply committed to the ongoing refinement of Server-Side
Rendering (SSR) capabilities. Over time, they’ve introduced a series of enhancements to
SSR applications, aiming to provide a smoother and more efficient experience for both
developers and end-users. The team’s focus has been on achieving the goal of a fully
hydrated application, which means that the application is not just server-rendered but
also preloaded with the necessary data and components, offering a seamless and
responsive user experience.
This concerted effort to improve SSR reflects the Angular team’s dedication to staying
at the forefront of web development technology. It’s an exciting journey of innovation,
and it’s intriguing to anticipate how these ongoing efforts will shape the landscape
of Angular in the future. The advancements in SSR hold the promise of further
enhancing the performance, SEO-friendliness, and overall user experience of Angular
applications, making them even more competitive and appealing in the dynamic world
of web development.
~ Balram Chavan
Google Developer Expert
Challenge:
Previous experimental features related to the Angular building systems affected
only the building process and not the development process, especially in the case
of the development server with hot-reload.
You can enable esbuild and Vite by updating your angular.json file:
...
“architect”: {
“build”: {
“builder”: “@angular-devkit/build-angular:browser-esbuild”,
...
Benefits:
Improvements in the Angular building system bring:
• An improved developer experience
• Reduced time and costin heavy CI/CD processes
Please note that these changes are still in experimental mode.
Required inputs
Dev Experience
Challenge:
Until Angular 16, it was not possible to mark inputs as required, but there was a common
workaround for this using a component selector:
Unfortunately, this was far from ideal. The first thing was that we polluted the
component selector. We always had to put all required input names to the selector,
which was especially problematic during refactors. It also resulted in a malfunction of
the auto-importing mechanisms in IDEs. And second, forgetting to provide the value for
an input marked this way meant the error was not very accurate, as there was no match
at all for such an “incomplete” selector. You can see this here:
ERROR
src/app/app.component.html:1:1 - error NG8001: ‘app-test-component’ is not a known element:
1.If ‘app-test-component’ is an Angular component, then verify that it is part of this module.
1.<app-test-component></app-test-component>
~~~~~~~~~~~~~~~
src/app/app.component.ts:5:16
5 templateURL: ‘./app.component.html’,
~~~~~~~~~~~~~~~
Solution:
The new feature allows us to explicitly mark the input as required, either in the @Input
decorator:
@Component({
...
inputs: [
{name: ‘title’, required: true}
]
})
However, the new solution has two serious drawbacks. One of them is that it only works
in AOT compilation and not in JIT. The other drawback is that this feature still suffers from
the strictPropertyInitialization TypeScript compilation flag, which is enabled by default
in Angular. TypeScript will raise an error for this property since it was automatically
declared as non-nullable but not initialized in the constructor or inline.
ERROR
src/app/test-component/test-component.component.ts:9:3 - error TS2564: Property ‘title’ has no initializer and is not
9 title: string;
~~~
This means that you still need to disable this check here e.g. by explicitly marking this
property with a non-null assertion operator, even though it has to be provided in the
consumer template:
Benefits:
The existing workarounds are replaced by a new solution with a very simple and
straightforward syntax.
Dev Experience
Challenge:
Angular interprets all static HTML attributes as strings. For example, if boolean attributes
are considered true when they are present on a DOM node,i.e. “disabled,” Angular,
by default, interprets them as strings.
Solution:
Since the release of Angular 16.1, we can provide an optional transform function for the
@Input decorator. This allows us to simplify the process of transforming values and
discontinue the use of setters and getters that have been used for this purpose so far.
Transform function:
@Component({
selector: ‘app-foo’,
template: ``,
standalone: true,
})
export class FooComponent {
@Input({ transform: toNumber }) width: number;
}
Usage in template:
Benefits:
Transform functions are pure functions, so they improve readability, reusability and
testability.
Challenge:
Obtaining router-related data inside components is not very comfortable. We have to
inject an ActivatedRoute token, subscribe to its properties, manage these subscriptions
to ensure no memory leaks, and so on.
Solution:
Angular version 16 brings another interesting feature related to component inputs: the
ability to bind them directly to the current route variables, such as path params and
query params. This eliminates the need to inject ActivatedRoute into the component in
order to use router data.
With this feature, data is being bound only to the routable components present in the
routing configuration, and inputs of children components used in the templates of
routable routes are not affected. Route data is matched with inputs by name,or input
alias name if present. This is done so there is more than one piece of data that can
potentially be put as the input value.
The list below shows the precedence of data being bound to input property if the names
are the same:
There is much more complexity if we consider “inheriting” data from places like the
parent route configuration and the parent component presence.
bootstrapApplication(AppComponent, {
providers: [
provideRouter(
[
{
path: ‘example/:id’,
data: {
bar: true,
},
resolve: { baz: () => ‘example string’ },
loadComponent: () => import(‘./app/todo/todo.component’),
},
],
withComponentInputBinding()
),
],
});
@Component({
selector: ‘example-cmp’,
standalone: true,
template: ‘’,
})
export default class ExampleComponent {
@Input() id!: string;
@Input() bar!: boolean;
@Input() baz!: string;
}
Benefits:
Router data input bindings simplifies the task of transmitting router data to the routed
components, consequently diminishing the requirement for repetitive code and dealing
with extra RxJS subscriptions.
Dev Experience
Challenge:
The cleanup process was a common problem Angular programmers had to deal with,
especially when we wanted to implement a component/directive lifecycle with long
RxJS subscriptions. The standard way to do this was to use an OnDestroy lifecycle
hook to complete all relevant streams and execute other cleanup actions. However,
this caused some overhead and unwanted boilerplate code. Another way to achieve
this implementation was to use third-party solutions like @ngneat/until-destroy, but
as opposed to built-in ones, they can introduce compatibility issues and less seamless
integration.
Solution:
In the new Angular version, we receive a brand new injectable for registering cleanup
callback functions that will be executed when a corresponding injector is destroyed.
@Component({
...
})
export default class MyComponent {
constructor() {
interval(3000).pipe(takeUntilDestroyed()).subscribe(
value => console.log(value)
);
}
}
Benefits:
The new operator is a convenient way to avoid memory leaks without dealing with
OnDestroy lifecycle hooks and subscription references. DestroyRef also allows you to
deal with other cleanup tasks in any way that fits your needs.
Dev Experience
Challenge:
When we don’t use a content projection mechanism, we are not placing any content
between tags of the Angular components we use in templates. HTML specification
contains many self-closing tags for nodes without inner HTML (i.e. <img />, <input />,
<br />), but in Angular, we always had to repeat the same name in opening and closing
tags, as follows:
<app-your-component-name [foo]=”bar”>
</app-your-component-name>
Solution:
Self-closing tags is a highly requested feature that arrived in Angular version 16. You can
use self-closing tags for your components.
This feature is optional and backward compatible, so you can continue to use
the standard approach, especially when using content projection.
<app-your-component-name [foo]=”bar”/>
Benefits:
Angular template syntax gets easier and more readable.
Dev Experience
Challenge:
There was no convenient way to inject dependencies outside of construction time, like
after user interaction or conditionally after resolving some asynchronous value.
Solution:
An “inject” function is a function that Injects a token from a current injection context.
We mostly use it during the construction time of classes being instantiated by the DI
system. Examples of classes include components, pipes and injectable services.
There is, however, a possibility to call “inject” at any time of the life cycle if we use the
“runInInjectionContext” function. This allows us to instantiate dependency on demand
after a user interaction.
@Injectable({
providedIn: ‘root’,
})
export class MyService {
private injector = inject(EnvironmentInjector);
someMethod(): void {
runInInjectionContext(this.injector, () => {
const otherService = inject(OtherService);
});
}
}
Benefits:
We get a possibility to inject dependencies at any time, as long as we have a reference
to the injector. This approach can improve application performance if we combine it with
lazy loading.
Challenge:
There was no way to generate a new project as a standalone from the beginning. We
had to manually remove AppModule and rewrite the bootstrapping process to
a standalone version with a bootstrapApplication function call. All components,
directives and pipes in such a project were generated using built-in code generators in
a non-standalone version by default.
Solution:
Angular version 16 introduced a new flag for CLI command with which we can generate
a new Angular project.
The project output with such a flag is simpler compared to the old ngModule-based
version. Generators for components, directives and pipes in this project will also create
standalone versions by default.
Benefits:
Kickoff of a new standalone project is made very easy, increasing overall project efficiency.
Typescript/Node.js support
Angular v16 brings support for TypeScript 5.0, and Angular v16.1 for Typescript 5.1. This
results in further computation time, memory usage and package size optimizations,
as well as many feature enhancements.
Dev Experience
Challenge:
Typescript supported custom experimental decorators for years. They’re familiar to every
Angular Developer, as we use them to define things like modules, components, injectable
services, pipes, directives, inputs, outputs and injections in constructor arguments. They
were implemented long before TC39 decided on a decorator’s standard, and now there
is a mismatch between the old TypeScript and the new ECMAScript decorator. Such
mismatch can cause compatibility and integration issues for developers.
Solution:
TypeScript 5.0 supports the new official ECMAScript decorators. This results in better
typing, like the ClassMethodDecoratorContext type which impacts meta information
like method name, access modifier and the extra function addInitializer
There is one important difference between the old and new implementation - decorators
used in the constructor parameters will not work, as the standard doesn’t support the
following code:
Benefits:
We’re up to date with the official ECMAScript standard with improved typings. We no
longer need to rely on the TypeScript custom implementation without its JavaScript
counterpart. Instead, we can use a solution that will be directly supported by all modern
browsers.
Dev Experience
Challenge:
Typescript supported custom experimental decorators for years. They’re familiar to every
It is uncomfortable to compose TypeScript configuration files with a single file extension,
especially in a mono-repository where multiple applications or libraries are involved.
This process requires us to create a chains of extensions as follows:
Solution:
Typescript 5.0 allows us to extend multiple tsconfig files.
// tsconfig1.json
{
“compilerOptions”: {
“strictNullChecks”: true
}
}
// tsconfig2.json
{
“compilerOptions”: {
“noImplicitAny”: true
}
}
// tsconfig.json
{
"extends": ["./tsconfig1.json", "./tsconfig2.json"],
"files": ["./index.ts"]
}
Dev Experience
Challenge:
Before Typescript 5.0, the language required all constant enum members to be string/
numeric literals, like 1,2, 300, “foo” or “bar,” for an enum to make it a union enum. In such
a case, union enum members become types as well. That means that certain members
can only have the value of an enum member. It also means that enum types themselves
effectively become a union of each enum member.
Solution:
In TypeScript 5.0, all enums, even the ones with computed members, are converted into
union enums. All members of all enums can be referenced as types and all enums can
be successfully narrowed.
The following example with computed enum members is correctly interpreted
in TypeScript 5.0 and above:
Benefits:
This feature brings more flexibility when defining types and more intelligent type
inference by the TypeScript transpiler.
Dev Experience
Challenge:
In a getter/setter pair, the get type had to be a subtype of the set type, which potentially
limited the ability to return more specific or transformed data types through getters.
Solution:
Since the release of TypeScript version 5.1, we can specify two completely unrelated types
for a getter/setter pair.
interface CSSStyleRule {
// ...
/** Always reads as a `CSSStyleDeclaration` */
get style(): CSSStyleDeclaration;
/** Can only write a `string` here. */
set style(newValue: string);
// ...
}
Benefits:
The developer gains more flexibility by being able to cover edge cases that require
different types.
Signals
Deferred Loading
Angular v17
release date: 11.2023
Angular 17 marks a pivotal update in the framework’s evolution, introducing streamlined
features and setting a robust foundation for future advancements in signals and
template syntax. In this version, Angular also continues its journey towards enhancing
performance and improving SSR.
Note:
Signals are introduced and described in the “Angular 16” chapter. Here we will focus on
the changes that have occurred since then.
Challenge:
The Angular signals library, in its developer preview phase, encountered some
modifications and adjustments due to feedback from the Angular community. Various
Angular developers raised doubts related to mutability and the change notification
system in the initial proposal.
Solution:
In Angular 17, signals became stable, so we could confidently use them in commercial
applications. At the end of the developer preview, we received two significant changes.
The first change was the removal of the ‘mutate’ function that was previously used to
mutate the value stored by the signal. The mutate function skipped comparing values
because its purpose was to modify the value of the signal by design. Now, it is
recommended to use only the update function.
The second change had to do with the implementation of the default function for
comparing signal values.
The upgrade of the API to the stable version does not include the "effect" function,
as there is still ongoing discussion about its semantics and potential improvements.
A significant change is that if all components in the application use the OnPush change
detection strategy and a new signal value triggers Change Detection in a specific
component template, only this component is marked as dirty and its ancestors are
notified about the change. This “local” change detection can majorly affect application
performance.
It is important to note that Angular 17 still does not include signal-based component
implementation, even in the developer preview mode. When this implementation arrives,
it is supposed to revolutionize the change detection system, because components will
not use zoneJS and DOM recalculation will only happen after the values related to the
signal view are changed.
Benefits:
The stabilization of the Angular signals library in Angular 17 lays solid groundwork
for future advancements, particularly in moving away from zone.js and towards
signal-based components. This shift is a step towards change detection system
transformation, which promises enhanced performance and efficiency in application
development.
At this juncture, I hold no particularly strong opinion on the signals library. My perpetual
quest revolves around enhancing both user experience (UX) and developer experience
(DX). Nonetheless, I avoid excessive “hype” concerning the introduction of signals at the
framework's core, opting instead for a rational assessment of the potential opportunities
signals may herald in the future. A substantial benefit would arise if we could seamlessly
transition away from zone.js, aligning with our overarching objective of establishing
a viable route toward creating fully zoneless applications (as one of the goals).
~ Artur Androsovych
Angular Expert
Signals are becoming a mainstream technique, being introduced in the most popular
frontend frameworks, the reason being that it is the perfect technique for fine-grained
synchronous reactivity. For a long time, we used to handle all states in an asynchronous
reactive approach using RxJS, whereas state management itself is a synchronous task,
such that RxJS is not the right tool by default. This overcomplicated a few use cases
and is the reason for unexpected glitching. This is a lot simpler with signals. Additionally,
this fine-grained reactive primitive can, and will, be used for fine-grained and zoneless
change detection in the future, when signal-based components land in Angular. This
is no small change, and will rather change the way we develop reactive Angular
applications completely.
~ Stefan Haas
Nx Champion
Signal inputs
Challenge:
The current implementation of component inputs is not very reactive. In order to listen
for changes, we use component lifecycle hooks. That means that if we want the input
values to interact with the Signal API, we need to handle the logic manually.
Solution:
Angular version 17.1 enables signal inputs for components. This means we no longer use
the decorator. Instead, a dedicated function defines the input:
This mechanism allows you to simplify the reactivity of the component, as it allows you
to define computed signals and side effects for input value changes. There is no longer
a need to use ngOnChanges lifecycle hook.
constructor() {
effect(() => {
console.log(‘logging: ’ + this.name());
})
}
}
The Signal input API has extra capabilities compared to its standard counterpart, such as
providing default values, marking input as required, setting aliases, and various transform
functions.
Benefits:
Signal inputs mark a significant step towards the deeper integration of signals into the
ecosystem and transforms the way we deal with component input changes.
This feature significantly enhances the developer experience and code clarity by
streamlining the management of component inputs and facilitating more intuitive
coding practices.
Challenge:
The standard control flow (if/else, switch/case, loop in component templates), based
on structural directives, has a few disadvantages. For example, the boilerplate, which
is large compared to other frontend frameworks, is necessary even for a single if-else
statement.
Solution:
The introduction of a new control flow to templates is one of the biggest changes
in Angular v17. It is the first step to moving away from built-in structured directives,
whose current design would not work in zoneless signal-based applications.
The new syntax is based on a structure called a block. Its appearance significantly
differs from what we have seen in templates. We start each block with an "@" prefix
and then use a syntax very similar to the one we know from JavaScript.
The change affects the three most commonly used structured directives: ngIf,
ngSwitch and ngFor. At this point, there is no planned implementation of custom
blocks.
An if/else statement:
A switch/case statement:
@switch (fruit) {
@case 'apple' {
<apple-cmp />
}
@case 'banana' {
<banana-cmp />
}
@default {
<unknown-fruit-cmp />
}
}
<ul>
@for (item of items; track item.id) {
<li>{{ item.name }}</li>
} @empty {
<li>No items...</li>
}
</ul>
The loop has received the most valuable improvements out of all the structures:
• The @empty block is available, which allows us to display the content when the
list we iterate over is empty.
• It is no longer necessary to create a special trackBy function to pass it as an
argument. Instead, we only need to specify the unique key of the object to be tracked.
• The @for block requires the use of the track function, which significantly
optimizes the process of rendering the list and managing changes without the need
for developer interference.
Since we have two ways of using the control flow, you may ask : what will happen to the
directives we are familiar with? In version 17, they remain unchanged. But with the arrival
of future versions and the exit of the new control flow from the developer preview, they
will go into a deprecated state.
However, there is no need to worry about refactoring. The Angular Team has created
a scheme that automatically migrates the control flow to the new syntax. In most cases,
the scheme should handle the transition to the new syntax without a programmer’s
interference. To switch to the new syntax, all you need to do is execute the following
command:
ng generate @angular/core:control-flow
Benefits:
The new control flow in Angular offers a more succinct and readable syntax,
significantly reducing boilerplate in templates. It ensures smoother integration with
future signal-based change detection systems, enhancing application performance.
Additionally, it lays the groundwork for advanced features such as deferred loading,
contributing to optimized load times and a better overall user experience.
Expert Opinion:
The new control flow is fabulous. The syntax is quite similar to the JavaScript syntax, and
the readability has increased. This new syntax is what we are waiting for. It’s also more
similar to JSX (not equal), but this can reduce the gap with React, and that can help
React developers jump into the Angular environment. With this new approach, we can
focus on the view’s logic and not on what Angular needs to show our logic correctly;
that’s a fantastic improvement for the developers and reduces the entry-level in the
framework.
~ Luca Del Puppo
Google Developer Expert
~ Fatima Amzil
Google Developer Expert
Challenge:
A lack of lazy loading in a web app can lead to slower page load times and increased
bandwidth usage, as all content is loaded at once regardless of its immediate
necessity. As long as Angular has lazy-loading modules in routing, there is no simple
and convenient way to lazy load individual components, even though it’s achievable
with dynamic import() and ngComponentOutlet.
Solution:
Angular version 17 introduces the new lazy-loading primitive called "defer," based on the
syntax introduced in the new control flow. This extremely useful mechanism allows
a controlled delay in the loading of a page’s selected elements. That is particularly
To control when to defer a block’s content, use predefined conditions: when and on. You
can use them individually or in any combination, depending on when you want to load
the content.
“When”: defines a logical condition that will load the block’s content when it receives
a true value.
An important note is that once the block’s content has been asynchronously loaded,
there is no way to undo that loading. If we want to hide the block’s contents, we need to
combine the @defer block with the @if block.
It is worth noting that loading content, as in the case of when, is a one-time operation.
“Prefetch”: There may be situations where we want to separate the process of fetching
content from rendering it on the page. In such a case, we need the prefetch condition.
It allows us to specify the moment, using the previously mentioned triggers, when the
necessary dependencies will be downloaded. As a result, interaction with this content
becomes much faster, resulting in a better UX.
We also have three very useful, optional blocks we can use inside the @defer block:
@placeholder - used to specify the content visible by default until the asynchronously
loaded content is activated. Example:
The "minimum" condition allows you to specify the minimum time after which
the delayed content can be loaded. In the example used above, this means that
even if the condition is met immediately, the content will be swapped after 2 seconds.
@loading - the content of this block is displayed when the dependencies are being
loaded. Example:
Within this block, we can also use the minimum condition, which works the same way as
within the @placeholder. It indicates the minimum time for which the block’s content will
be visible. We can also use the “after” condition, which indicates the amount of time it
will take for the block’s content to appear. If it takes less than 100ms to load, the loader
will not appear. Instead, `<deferred-cmp />` will replace it immediately.
@error - represents the content rendered when the deferred loading failed for some
reason. Example:
When using the defer block together with the @error block, it is possible to use
a special timeout condition. This condition allows you to set a maximum loading time. If
dependencies take longer than the specified time, the contents of the @error block will
be displayed. Inside this block, the user has access to the $error variable, which contains
information about the error that occurred during the loading process.
Benefits:
Deferred loading in Angular enhances performance by reducing initial bundle
size, speeding up load times, and enabling controlled, asynchronous loading of
individual components based on user interaction or other predefined conditions.
This leads to a more efficient and user-friendly experience.
Deferred loading opens a new way to reduce the bundle size of every component and
introduces a new way to load only essential code needed for the current view. This
feature will probably be one of the leading solutions to reduce the page size in a Server
Side Render application; it helps to render only the needed parts and skip the dynamic
content that isn't required on the page start-up or for the SEO.
As for the deferred loading feature, it's truly incredible! With this feature, we can
lazily-load content within an Angular template. It's much more than just simple
lazy loading; we can load chunks based on conditions and triggers and even prefetch
in advance. This is bound to revolutionize the way we construct our Angular templates.
~ Fatima Amzil
Google Developer Expert
Challenge:
When we used the NgComponentOutlet structural directive to create dynamic
components, there was no convenient way to pass the data to them. The usual solution
was to create a new injector and transfer data by a custom injection token.
Solution:
In Angular 16.2, we received a possibility to bind data to inputs of a component created
with NgComponentOutlet.
In the child component from the example above, we have to create @Input with a ‘foo’
name, or alias and the data will be bound from the parent.
Benefits:
The new function simplifies the data passing process, making it more declarative. This
improves code readability and developer experience.
Performance UX
Challenge:
Animations are always downloaded while the application is bootstrapped, even though
in most cases, animations occur while the user is interacting with an element on the
page. This results in increased bundle size.
Solution:
Animation lazy loading is a new functionality in version 17 that solves this problem by
introducing the ability to asynchronously load code that is associated with animations.
And that's it! Now we just need to make sure that all functions from the @angular/
animations module are only imported into dynamically loaded components.
Controlling imports in our application is easy, but the process can become problematic
when we do it with libraries. An example of such a library is @angular/material, which
relies heavily on @angular/animations, making it very likely that the module
responsible for animations will be pulled into the initial bundle.
Benefits:
Lazy loading of any kind of resources enhances user experience by speeding up initial
page load times, saving bandwidth, prioritizing critical resources, and potentially
improving website performance and SEO.
View Transitions
UX
Challenge:
There is no convenient way to implement smooth animated transitions between pages
in Angular.
Solution:
Support for the View Transition API has been introduced. This is a relatively new
mechanism that allows us to create smooth and interactive transition effects between
different views of a web page. Thanks to this API, we can make changes to the DOM tree
while an animation is running between two states.
First, we need to import the ‘withViewTransitions’ function at the bootstrap point of our
application.
Now, the application immediately gains a subtle input and output effect when
changing the URL. Of course, we have the ability to create custom animations. In the
example below, the transition effect was extended to 2 seconds by using prepared
pseudo-elements in the `styles.css` file.
This example is a very small sample of what we can achieve with this API. If you are
interested in the practical use of this mechanism, We encourage you to read the
material available in the Chrome browser documentation.
How does this feature work internally? When navigation starts, the API takes a screenshot
of the current page and puts it in ::view-transition-old pseudoelement. It also renders
a new page, puts it in view-transition-new and plays the animation between them.
Benefits:
The View Transitions API simplifies the creation of smooth and cohesive navigation
animations, enhancing user experience by providing a seamless visual transition
between different states or views of a web application.
Challenge:
Until now, Angular's build system primarily relied on Webpack for compiling applications,
requiring separate builders for different purposes like production builds, development
server, server-side rendering, and prerendering. This led to more complex configurations
in angular.json, slower build processes due to repetition of common steps, and less
efficient module loading as it did not fully utilize ECMAScript Modules (ESM).
Solution:
In Angular v17, we received the new 'application' builder, which streamlines the build
process by using @angular-devkit/build-angular:browser-esbuild as its core. This
builder simplifies configurations by consolidating various tasks such as production
builds, server-side rendering (SSR), and prerendering into a single, more efficient
process. It enhances performance by executing common build steps only once and
fully supports ECMAScript Modules (ESM), leading to faster build times and more
efficient, modern module loading.
To apply these changes to an existing Angular project, change the builder from:
@angular-devkit/build-angular:browser
to:
@angular-devkit/build-angular:application
If your application supports SRR capabilities, you might need a few extra configuration
changes (in such case check the official documentation for details).
The new application builder provides the functionality for all of the preexisting builders:
• browser
• prerender
• server
• ssr-dev-server
The usage of Vite build pipeline is encapsulated within the ‘dev-server’ builder, with no
Benefits:
Thanks to the unified solution, faster build-time performance is also brought to SSR apps.
Using the same builder for both types of applications reduces the risk of potential
differences resulting from using different bundlers. For new build systems with SSR & SSG,
‘ng build’ gets its speed increased by up to 87%, and ‘ng serve’ gets an 80% increase
in speed.
Performance UX
Challenge:
Full Hydration presented in Angular version 16 was in developer preview mode, which
could have stopped us from using it in applications since it was not yet stable.
Solution:
From version 17, the solution is marked as stable, which means it is considered safe
for use in a production environment.
...
bootstrapApplication(RootCmp, {
providers: [provideClientHydration()]
});
Benefits:
We can safely enjoy the benefits of hydration such as better UX (faster loading and
interactivity, no more flickering) and enhanced SEO in a production environment.
Challenge:
The CLI does not take several new features from recent releases into account and uses
older solutions by default.
Solution:
In Angular 17, applications generated by ‘ng new’ will be standalone by default and will
use Vite as the default build system. All relevant code generators (i.e. for components,
directives, pipes) will produce standalone output as well.
You can use the following migration to convert existing projects to the standalone APIs:
ng generate @angular/core:standalone
‘ng-new’ also supports the ‘--ssr’ flag or alternatively includes a prompt asking if we
wan’t to enable SSR or SSG by default, including hydration.
Do you want to enable Server-Side Rendering (SSR) and Static Site Generation
(SSG/Prerendering)? (y/N) y
To try out the new built-in control flow syntax in your existing project, you can use the
following migration:
ng generate @angular/core:control-flow
Benefits:
New features in the framework are becoming more accessible, and we get ready-made
configurations out-of-the-box right from the start, which speeds up the project launch.
Dev Experience
Challenge:
Debugging dependency injection (DI) has always been problematic. If there were errors,
they were always caused by the inability to inject a specific token, and if a token was
successfully injected, there was no information about what injection context it came
from.
Solution:
The Angular Team implemented brand new debugging APIs related to dependency
injection. On top of that, they extended the capabilities of Angular Devtools and made it
possible to inspect DI in the runtime. It is possible to verify a component’s dependencies
in a component inspector, injection tree with a dependency resolution path and
providers declared in individual injectors.
Environment Hierarchy
Element Hierarchy
AppComponent LayoutComponent
Benefits:
The new debugging APIs for dependency injection in Angular helps developers to build
more reliable and efficient applications.
Dev Experience
Challenge:
The branding of Angular has been almost identical since the beginning of AngularJS,
which was released over 10 years ago. The framework documentation is also somewhat
outdated, often based on ngModules.
Solution:
With the premiere of Angular version 17, we also received a new graphic identification of
the framework and a new angular.dev - a home for Angular’s new documentation.
Benefits:
The new Angular.dev documentation makes it easier for developers to learn and use
Angular.
Angular v17 requires Typescript 5.2+ and Node.js v18+. Since 17.1, Angular also supports
Typescript 5.3. New versions bring a handful of interesting changes that may be useful in
Angular projects.
Dev Experience
Challenge:
There is no convenient way to explicitly manage resources with a specific lifetime.
For example, run some cleanup code when a given object reaches the end of its
life.
Solution:
The system for managing objects with a specific lifetime will be part of the ECMAScript
standard. For Typescript, it was already delivered in version 5.2. This system is inspired
by solutions from other programming languages, for example, the “using” syntax from
C# or the “try-with-resource” syntax from Java. It allows a programmer to manage the
resource declaratively, meaning an object is disposed when execution leaves the scope
where object has been defined, or imperatively by calling a Symbol.dispose method
manually.
In the example below, we define a manageable object inside the function scope. When
execution leaves the function context, the Symbol.dispose method is automatically
called. This happens even if there was an exception during processing. We no longer
have to wrap logic into the try/catch/finally block to make sure that clean-up logic is
executed in all cases.
function doSomething() {
using foo = new Foo();
// do something
if(someCondition()) {
// do another thing
return;
}
}
This feature also contains support for async disposable resources, Symbol.asyncDispose,
and extra methods for dealing with stacks like DisposableStack and AsyncDisposableStack.
Note that this feature is only available if you set the compiler target to es2022 and added
“esnext” or “esnext.disposable” to the “lib” array.
{
"compilerOptions": {
"target": "es2022",
"lib": ["es2022", "esnext.disposable", "dom"]
}
}
Benefits:
Explicit Resource Management enhances code cleanliness and safety by providing
a straightforward and efficient way to manage the lifecycle of resources. This ensures
that clean-up or disposal code is automatically executed when the object goes out of
scope or encounters an exception, without the need for extensive try/catch/finally blocks.
Dev Experience
Challenge:
There is no convenient way to explicitly manage resources with a specific
lifetime. For example, run some cleanup code when a given object reaches
the end of its life.
Solution:
Typescript gained support for optional names or labels for each element of the tuple.
The all-or-nothing restriction has been removed and labels go as far as preserving
the merging with other tuples.
Benefits:
The improvement enables greater flexibility and readability in TypeScript code.
Dev Experience
Challenge:
Old and well-known array methods like sort, splice or reverse, all update an array
in-place, meaning they mutate the original array. This can lead to unintended side
effects and make code harder to understand and debug, especially in complex
applications with shared state.
Benefits:
Using non-mutable array methods over methods that will mutate arrays in place
in the JavaScript language have multiple benefits. These include enhancing
code predictability, maintainability, and readability by avoiding unintended side
effects and ensuring consistent data state across different parts of an application.
Challenge:
Angular and Zone.js have been tightly connected from the beginning. While Zone.js
helps Angular track asynchronous operations and automatically manage change
detection, it can also slow down the application.Developers are often faced with the
problem of the extra load that Zone.js adds and the difficulty of manually managing
the detection of changes. Main Functions of Zone.js in Angular include:
These functions are key to Angular's ability to manage asynchronous actions and
update the view automatically. However, Zone.js adds performance overhead because
it has to track and wrap all these asynchronous tasks. In large apps with many asyn-
chronous calls, this can slow down performance. Techniques like running code outside
the zone can help, but they are tricky and can negatively affect the developer experience.
bootstrapApplication(RootCmp, {
providers: [provideExperimentalZonelessChangeDetection()]
});
The new change detection mechanism should only respond to data changes that are
extremely easy to detect from the signals. The new change detection cycle will be
scheduled when:
• A Signal updated
• Calls to changeDetectorRef.markForCheck()
• A subscribed Observable with the AsyncPipe receives a new value
• A component gets attached/detached
• Setting an input
Benefits:
By eliminating Zone.js, the application experiences less overhead, resulting in faster per-
formance, especially in applications with many asynchronous operations. We should
expect the code to become simpler.
Some combinations related to running code outside of the zone or just manually trig-
gering change detection should be rare cases which in effect will enhance developer
experience. Excluding the scenario of manually invoking change detection, it will actually
react to data changes, since data is what drives our applications, we will avoid unneces-
sary checks, improving overall performance and application responsiveness.
Additionally it should reduce application bundle size, improve core web vitals, speed
uppage loading time and simplify stack trace and debugging.
~ Aristeidis Bampakos
Google Developer Expert
If your app is already optimized for performance, zoneless will improve the performance
even more, but if the performance is already good enough for you, it would be a nice-
to-have. If you’re using OnPush Change Detection, it means that your app is already
zoneless compatible, so you can enable it without having any issues.
~ Enea Jahollari
Google Developer Expert
Removing Zone JS, it's one of the biggest changes for the Angular team in the end.
I think it's one of the ideas from one of the first releases of Angular. Now, after the release
of Ivy, I saw a lot of improvement in the framework at the end. With Ivy under the hood,
the framework is starting to be more community-driven, first of all, because Angular
team is able to release a lot of elements that are requested by the community. They're
also faster in their release process.
Challenge:
The current implementation of component inputs is not very reactive. In order to look for
the changes, we use component lifecycle hooks. That means that if we want the input
values to interact with the Signal API, we have to handle the logic manually.
Solution:
Angular version 17.1 enables signal inputs for components. This means we no longer use
the decorator. Instead, a dedicated function defines the input:
@Component({
selector: 'my-cmp’,
standalone: true,
template: `{{ name() }}`,
})
export class MyComponent {
name = input<string>();
}
This mechanism allows you to simplify the responsiveness of the component by letting
you define computed signals and side effects for input value changes. It is no longer
necessary to use the ngOnChanges lifecycle hook.
constructor() {
effect(() => {
console.log(‘logging: ’ + this.name());
})
}
}
Benefits:
Signal inputs mark a significant step towards the deeper integration of signals into the
ecosystem and transform the way we deal with component input changes. This feature
significantly enhances the developer experience and code clarity by streamlining the
management of component inputs and facilitating more intuitive coding practices.
Expert Opinion:
Don’t sleep on signals! While there may be some rough edges to migrating if you're
using RxJS for everything, signal will give you an even better developer experience and
performance!
~ Enea Jahollari
Google Developer Expert
Challenge:
Standard inputs in Angular are read-only and do not allow components to send new
values back to the parent components. This limitation restricts the creation of interactive
components that need to update the parent component's state based on user actions.
Solution:
Angular introduces model inputs, a special type of input that allows components to
propagate new values back to the parent component. Currently in developer preview,
this feature facilitates two-way binding, allowing for more dynamic interactions.
Model inputs are defined in much the same way as standard inputs, but with added
capabilities for two-way data binding. Here's how to define and use model inputs in
Angular:
@Component({
selector: 'custom-toggle',
template: '<button (click)="toggle()">Toggle</button>'
})
export class CustomToggle {
active = model(false); // This is a model input
disabled = input(false); // This is a standard input
toggle() {
this.active.set(!this.active());
}
}
@Component({
selector: 'app-root',
template: '<custom-toggle [(active)]="isActive" />',
})
export class AppComponent {
isActive = signal(false); // Writable signal
}
In this example, the isActive signal in the parent component (AppComponent) stays in
sync with the active model input in the child component (CustomToggle).
1. Two-Way Binding with Plain Properties:
You can also bind plain JavaScript properties to model inputs.
@Component({
selector: 'app-root',
template: '<custom-toggle [(active)]="isActive" />'
})
export class AppComponent {
isActive = false; // Plain property
}
@Directive({
selector: 'custom-toggle',
})
export class CustomToggle {
active = model(false); // Creates an output event "activeChange"
}
Benefits:
Model inputs have several advantages. They enable dynamic interactions by allowing
child components to update the state of parent components through two-way data
binding. This results in more interactive and responsive applications. Additionally, mod-
el inputs simplify code by reducing the need for additional properties and boilerplate
code, leading to cleaner and more maintainable codebases. They also enhance flexibil-
ity, making it easier to create custom form controls and other interactive components
that need to modify values based on user actions.
By improving the flexibility and interactivity of Angular components, the model inputs
make it easier to build dynamic and user-friendly applications. This leads to better user
experiences and more efficient management of complex state changes within the An-
gular components.
Signal queries
Challenge:
Similar to the old inputs, the current implementation of view queries is not very reactive.
We need to use setters or observables to track when the queried dom changes.
Solution:
New functions have been introduced as an alternative to decorators. Each of them pro-
duces as a result a signal value of the queried DOM.
ViewChild:
The first of these is ViewChild().It’s a signal based replacement for @ViewChild().
We use it when we are looking for a single result in our component. Similarly to input() or
model(), we can also use the required option here.
ViewChildren:
Similarly, the ViewChildren function is the signal-based counterpart to @ViewChildren().
It is used for querying multiple elements within the component.
@Component({
template: `
<div #el></div>
<div #el></div>
<div #el></div>
`,
})
export class MyComponent {
firstSelector = viewChildren<ElementRef>('el');
// Signal<readonly ElementRef<any>[]>
secondSelector = viewChildren<ElementRef<HTMLDivElement>>('el');
// Signal<readonly ElementRef<HTMLDivElement>[]>
}
// parent.component.ts
@Component({
template: `
<ng-content></ng-content>
`, // Zwróćcie uwagę na tag ng-content
standalone: true,
selector: 'app-parent'
})
export class ParentComponent {
content = contentChild(ChildComponent);
// Signal<ChildComponent | undefined>
contentElements = contentChildren(ChildComponent);
// Signal<readonly ChildComponent[]>
}
Benefits:
The new signal-based approach simplifies the codebase, making it easier to read and
maintain. Signals provide a more reactive way of handling DOM queries, automatically
updating as the queried elements change. This results in a better developer experience
with less need for manual settings and immediate improvements in responsiveness. This
leads to a smoother development process and less boilerplate code.
Output syntax
Challenge:
Inputs have been changed to be signal based. The output so far was still in the old
syntax. This meant we needed decorators to declare them. What’s more, there was
inconsistency in terms of the type safety, as the emit function was accepting following type:
T | undefined which was allowing us to emit an event without value even though we had
typed it to be specific type.
onEvent(): void {
this.oldOutput.emit(); // It’s ok even though we typed it as string
}
}
Solution:
A new output function has been introduced. A new output function has been introduced.
Mostly it's just a syntax adjustment, it has nothing to do with signals. For example, it doesn't
mean that a sent value is immediately a signal, as it is with input, where sent values are
always read as signals.
@Component(...)
export class MyComponent {
valueChanged = output<string>();
Changes have also been made to the return type of the output function. It now returns
OutputEmitterRef<T>, which prevents the output of a value inconsistent with the declared
one. The example we provided in the challenge section will generate an error when using
the new syntax.
@Component(...)
export class MyComponent {
newOutput = output<string>();
onEvent(): void {
this.newOutput.emit(); // ERROR: Expected 1 arguments, but got 0.
}
}
Challenge:
Angular, despite its extensive feature set and developer-friendly tools, has faced
significant competition from other frameworks like React and Vue. A major challenge
has been balancing the need for performance optimization with maintaining good
developer experience. In addition, Angular relies on zone.js for reactive programming,
which has introduced overhead and complexity that affects optimal performance,
especially in performance-critical applications used by millions of users, such as those
developed by Google.
Solution:
To address these challenges, the Angular team has begun a collaboration with Wiz,
an internal web framework developed by Google and known for its performance opti-
misations in applications such as Google Search and Photos. This collaboration aims to
integrate Wiz's performance-related features into Angular's developer tools, starting with
the introduction of Angular Signals.
Benefits:
The collaboration between Angular and Wiz brings several significant benefits. Integrating
Wiz's performance optimizations with Angular improves the overall efficiency and speed
of applications, addressing one of the keychallenges faced by Angular developers.
This not only reduces the overhead mostly associated with zone.js but also simplifies
reactive programming, making it more intuitive and less prone to errors. As a result, de-
velopers can enjoy a smoother, more productive coding experience.
Moreover, the synergy between the two teams is good for continuous innovation, ensur-
ing that both frameworks benefit from shared insights and technological advancements.
Expert Opinion:
The Angular and Wiz collaboration will try to blend together the best parts of both
frameworks. In Angular, we will see improvements in hydration through Wiz's event dis-
patch library, which can record and replay events on the client while it is not yet inter-
active. In Wiz, we will see improvements in the state management with the extended
usage of signals.
We are not going to see Wiz switching to a full open-source model. Rather, we will see
some of its parts becoming open source through the Angular framework.
~ Aristeidis Bampakos
Google Developer Expert
What are the core aspects and benefits of merging Angular and Wiz? When can we
expect Wiz to switch to an open-source model?
Maybe Google has a secret sauce that makes things super fast. How fast? Think how
performant Gmail and Google search are. That's WIZ in action!
Some of WIZ's features may become open source and others will find their way to An-
gular. We have already seen how great the deferrable views are, which is WIZ’s influ-
ence on Angular.
~ Fanis Prodromou
Google Developer Expert
Challenge:
One of the well-known challenges in Angular development has been handling scenarios
where a component may not receive any projected content. In such cases, developers
traditionally had to implement complex workarounds to ensure that component still dis-
plays useful default content. This lack of native support for fallback content in ng-con-
tent has been a limitation, causing additional overhead and complexity to component
design and development.
Solution:
Angular v18 introduces a significant enhancement with built-in support for fallback
content in ng-content slots. This new feature simplifies the process of defining default
content that will be displayed if no content is projected into the component. By allowing
developers to specify fallback content directly within the ng-content tag, Angular v18
improves component development, making it more intuitive and efficient.
@Component({
standalone: true,
selector: 'my-component',
template: `
<ng-content select="header"> Default header </ng-content>
<ng-content> Default main content </ng-content>
<ng-content select="footer"> Default footer </ng-content>
`,
})
export class MyComponent {}
In this example, if no content is provided for the header, main content, or footer, the de-
fault values ("Default header", "Default main content", "Default footer") will be displayed.
This feature significantly reduces the need for conditional logic and additional checks
within the component's logic to ensure that fallback content is shown.
Additionally, the new feature simplifies the component development process. By em-
bedding fallback content directly into the component's template, developers can avoid
complex workarounds. This approach improves the overall developer experience.
Dev Experience
Challenge:
In previous versions of Angular, route redirects were limited to static strings. This limita-
tion made it difficult to handle redirects that depend on runtime conditions or complex
logic. Developers needed a more flexible way to define redirects based on dynamic data,
such as query parameters or application state.
Solution:
Angular version 18 introduces a new feature that allows redirectTo to accept a function
that returns a string. This function can implement complex logic, enabling more flexi-
ble and dynamic redirects. It essentially receives the current route's context, including
query parameters, allowing developers to tailor the redirection logic to specific runtime
conditions.
Consider a scenario where you need to redirect users based on the presence of a use-
rId query parameter. If the userId is provided, users should be redirected to their profile
page. If not, an error should be logged, and users should be redirected to a "not found"
page.
Here’s how this can be achieved using the new redirectTo function feature:
In this example:
Benefits:
The introduction of function-based route redirects in Angular greatly enhances the flexibil-
ity of routing in applications. It allows developers to define dynamic redirection logic based
on the application's current state or runtime data. This means that developers can easily
implement complex routing requirements without resorting to workarounds or additional
code structures.
This feature not only improves the developer experience by simplifying the implementation
of dynamic routing but also enhances the maintainability and readability of the routing
code. It streamlines navigation logic, making it more intuitive and reducing the potential for
errors, thus improving overall application reliability.
Dev Experience
Challenge:
In previous Angular versions, managing complex navigation patterns and using Navi-
gationExtras with Guards and Resolvers could be cumbersome and less maintainable.
Developers struggled to handle advanced navigation scenarios, which required a more
streamlined and flexible approach to manage redirections and navigation states.
Solution:
Angular version 18 introduces the RedirectCommand class, designed to manage Naviga-
tionExtras more effectively. This class allows for improved redirection capabilities within An-
gular applications, particularly when used in conjunction with Guards and Resolvers. The
RedirectCommand class makes it easier to implement and maintain complex navigation
logic, enhancing both flexibility and developer experience.
Consider a scenario where a route guard needs to redirect users based on certaincondi-
tions, such as checking user permissions or application state. The new RedirectCommand
class simplifies this process by allowing developers to create a UrlTree and manage Navi-
gationExtras in a concise manner.
Here’s an example that demonstrates the use of RedirectCommand within a route guard:
Benefits:
The introduction of the RedirectCommand class in Angular 18 provides several advan-
tages. It increases the flexibility and maintainability of routing logic, particularly in the
complex navigation scenarios involving Guards and Resolvers. This feature streamlines
the management of redirections and NavigationExtras, reducing boilerplate code and
making it easier to implement robust navigation patterns. By simplifying the handling
of challenging navigation tasks, the RedirectCommand class improves developer pro-
ductivity and the overall developer experience in Angular applications.
This feature makes it more straightforward for developers to manage advanced redi-
rection scenarios, improving the reliability and readability of navigation-related code.
This leads to a better-maintained applications and a smoother development process.
Dev Experience
Challenge:
Debugging hydration issues in Angular applications used to be challenging. Developers
lacked visibility into the hydration status of components, making it difficult to identify and
resolve hydration errors effectively. This limited insight often led to extended debugging
sessions and reduced productivity.
Solution:
Angular has updated Angular DevTools to enhance the debugging experience by visual-
izing Angular’s hydration process. This update includes new icons next to each compo-
nent indicating its hydration status. Additionally, developers can enable an overlay mode to
see which components have been hydrated on the page. If there are any hydration errors,
Angular DevTools will visualize them directly in the component explorer, providing immedi-
ate feedback and detailed information about the problem.
Dev Experience
Challenge:
Managing state changes in form controls has been a recurring challenge. Traditional-
ly, we have had to subscribe to multiple observables or use different methods to track
changes in form control values, status, and other states such as pristine or touched. This
approach can lead to increased complexity of the code, making it harder to maintain
and understand, especially in large applications with many form controls. There were
events we couldn't subscribe to at all, such as touched and untouched.
Solution:
Angular v18 introduces a unified approach to handling control state changes with a new
feature added to the AbstractControl class. This feature exposes an event observable that
tracks various state changes in form controls, such as value changes, pristine state, touch
status, and overall control status. By combining these state changes into a single observa-
ble stream, Angular simplifies the management of form control states.
@Component({
selector: 'app-my-form',
template: `
<form>
<input [formControl]="control">
</form>
`
})
export class MyFormComponent implements OnInit {
control = new FormControl('');
ngOnInit() {
this.control.events.subscribe(event => {
console.log(event);
});
}
}
Benefits:
The unified control state change events make it easier to track and manage form
control states by combining all state changes into one observable. This simplifies
the code, making it clearer and easier to maintain. It also improves the reliability
of handling user interactions and form submissions. Overall, this feature boosts
developer productivity and simplifies the development process.
New Documentation
Dev Experience
Challenge:
The previous Angular documentation site, angular.io, had several areas that could be
improved to enhance the learning experience for developers. Developers needed more
intuitive navigation, better search functionality, and interactive learning tools to get
started with Angular in a more effective way. What's more, some of the examples were
already out of date (e.g. syntax) and updating them to the latest standards was quite
difficult.
Solution:
Angular has launched a new documentation site, angular.dev, which is now the official
documentation website for Angular. This new site has a modern look and feel and includes
several enhancements aimed at improving the developer experience.
Features of Angular.dev:
2. Interactive Playground:
The site includes an interactive playground with examples, enabling developers
to experiment with Angular code snippets and see the results in real time.
4. Refreshed Guides:
The guides on angular.dev have been updated and improved to provide clearer,
more detailed explanations and instructions.
5. Simplified Navigation:
Navigation has been streamlined to make it easier for developers to find their
way around the site and access the resources they need.
Benefits:
The new angular.dev site significantly enriches the developer experience by providing
a more intuitive and engaging learning environment. The interactive tutorials and play-
ground allow developers to learn by doing, which can be more effective than just reading
documentation. Improved search and simplified navigation help developers find the infor-
mation they need quickly, reducing the time spent searching for answers and increasing
productivity. Additionally, the refreshed guides and modern design make the documenta-
tion more accessible and enjoyable to use.
By redirecting all requests from angular.io to angular.dev and ensuring that existing links
continue to work by forwarding to v17.angular.io, Angular has made the transition smooth
for developers. This ensures that the community can continue to access valuable resources
without disruption.
Visit angular.dev to explore the new site and take advantage of these improvements!
Challenge:
In Angular version 17, some Angular material and CDK components were removed from
hydration. This meant that these components would not retain their server-rendered
state and would be rerendered on the client side. This re-rendering could impact per-
formance and user experience, as the components had to be reinitialized and redrawn
after the initial load.
Solution:
Starting with Angular version 18, all Angular Material and CDK components are fully hy-
dration compatible. This means that these components will now retain their server-ren-
dered state and do not require rerendering on the client side. This change improves
performance by reducing the need for additional rendering work once the application
loads in the browser.
Benefits:
The update to make all Angular Material and CDK components fully hydration compat-
ible brings several benefits. It enhances the performance of Angular applications by
reducing unnecessary rerendering of components. This leads to faster load times and
a smoother user experience, as the components are ready to interact with immediately
after the initial server-side rendering. It also simplifies the development process by en-
suring consistent behaviour across all Material and CDK components, without the need
for special handling or workarounds for hydration issues.
Challenge:
A few months ago, Angular introduced experimental support for Material 3, the latest version
of Google’s Material Design guidelines. During this experimental phase, developers provided
feedback highlighting areas for improvement. The goal was to refine these components to
ensure they met the high standards expected by the developer community before releas-
ing them as stable. At the same time, Angular Material was still based on Material 2, which
made customization difficult. This lack of flexibility posed challenges for developers looking
to implement the latest design trends and tailor components to their specific needs.
Solution:
After listening to feedback and making the necessary adjustments, Angular has
now graduated the Material 3 components to stable status. This means that Material
3 is fully supported and ready for production use, providing developers with a polished
set of UI components that adhere to the latest Material Design guidelines. Additionally,
Angular Material 3 introduces tokens for theming, which greatly enhance customiza-
tion possibilities. These tokens allow for more granular control over component styling,
giving developers greater flexibility to tailor their applications to specific design re-
quirements.
Benefits:
The transition of Material 3 to stable status provides several key benefits. First, it provides
reliability, as developers can now use Material 3 components in production environments
with confidence, knowing that they have been thoroughly tested and refined. Second, the
components adhere to the latest Material Design guidelines, ensuring a modern and
consistent look and feel across applications. Third, the updated material.angular.io site
provides comprehensive documentation and resources, making it easier for develop-
ers to implement and customize Material 3 components. Together, these enhancements
simplify the development process and ensure that applications built with Angular and
Material 3 are visually appealing, consistent, and maintain high standards of user inter-
face design.
Dev Experience
Challenge:
Prior to TypeScript 5.3, the instanceof operator did not always work well with custom type
checks. This made it hard to correctly check the type of some objects, which could lead
to errors in the code.
Solution:
TypeScript 5.3 adds a new feature that allows the instanceof operator to use custom type
checks. If a class has a [Symbol.hasInstance] method, TypeScript will use it to check the
type of an object. This makes type checking more accurate.
interface PointLike {
x: number;
y: number;
}
Summary:
Before TypeScript 5.3, developers had to create manual type guard functions to handle
custom instance checks, which made the code less clean and increased the potential for
errors. This manual process involved writing functions to check whether an object met
certain criteria to be considered of a particular type, such as checking properties and
their types individually.
With the introduction of TypeScript 5.3, the instanceof operator can now leverage custom
type guards defined through the Symbol.hasInstance method. This allows developers to
embed custom type-checking logic directly within classes, making the type-checking
process more accurate and the code cleaner. The instanceof operator now automatically
uses this custom logic, simplifying the code and enhancing type safety.
Dev Experience
Challenge:
Using super incorrectly on instance fields could cause runtime errors because super only
works on prototype methods, not instance properties. This led to confusing bugs that
were difficult to diagnose and fix.
Solution:
TypeScript 5.3 adds checks to ensure that super is used correctly, preventing runtime
errors by issuing a type error when super is used on instance fields.
class Base {
someMethod = () => {
console.log("Base method called!");
}
}
class Derived extends Base {
someOtherMethod() {
super.someMethod(); // Error: 'super.someMethod' is 'undefined'
}
}
new Derived().someOtherMethod();
This improvement prevents runtime errors, making the code safer and easier to debug.
Benefits:
Checks for super property accesses on instance fields prevent runtime errors, making
code safer and easier to debug.
Dev Experience
Challenge:
Boolean value comparisons were not well understood by TypeScript, leading to inaccu-
rate type narrowing and potential type errors.
Solution:
TypeScript 5.3 improves the handling of boolean comparisons, enabling for accurate
type narrowing and more secure code.
Benefits:
Narrowing on comparisons to booleans improves type safety, reduces errors, and
enhances code clarity.
Dev Experience
Challenge:
Previously, type escaping in non-hoisted functions was inaccurate, leading to potential
type errors and less reliable code. This was particularly problematic in functions where
variables could change type or value multiple times, making it difficult for TypeScript to
keep track of the correct type.
Solution:
TypeScript 5.4 refines type narrowing in non-hoisted functions by considering the last
assignment point for type checking. This improvement ensures that TypeScript accu-
rately tracks the type of variables based on their most recent value, resulting in more
reliable and accurate type checks.
if (flag) {
value = "string";
} else {
value = 42;
}
// TypeScript now correctly infers the type of 'value' based on the last assign-
ment
if (typeof value === "string") {
console.log(value.toUpperCase()); // Works because 'value' is correctly in-
ferred as string
} else {
console.log(value.toFixed(2)); // Works because 'value' is correctly inferred as
number
}
}
Benefits:
Smarter narrowing in non-hoisted functions improves type accuracy, reduces type errors,
and improves the overall clarity and reliability of the code. This makes it easier for devel-
opers to write safe and precise code without worrying about incorrect type inferences.
Dev Experience
Challenge:
Template literal types in previous versions of TypeScript were limited in their expressive-
ness and flexibility. Developers faced challenges when trying to define complex types that
involved string manipulation and pattern matching, reducing the usefulness of template
literal types in certain scenarios.
Solution:
TypeScript 5.4 extends the capabilities of template literal types, making type definitions
more expressive and flexible. This enhancement makes it possible to create more com-
plex and precise types that better meet the needs of various coding scenarios, espe-
cially those involving dynamic string patterns.
Benefits:
Expanded template literal types improve the flexibility and expressiveness of type defini-
tions, making it easier for developers to work with complex string patterns and dynamic
types. This enhancement leads to clearer and more maintainable code, as types can now
more accurately reflect the intended data structures.
Dev Experience
Challenge:
Read-only arrays and tuples in previous versions of TypeScript had limited type infer-
ence and immutability guarantees. This made it challenging to work with immutable
data structures, as the type system did not always provide accurate type information or
enforce immutability effectively.
Solution:
TypeScript 5.4 enhances the handling of read-only arrays and tuples by improving type
inference and immutability guarantees. This ensures that the type system accurately
reflects the immutability of these data structures, provides better type information and
enforces immutability more effectively.
Benefits:
Enhanced read-only arrays and tuples improve type inference, guarantee stronger
immutability guarantees, and make it easier for developers to work with immutable data
structures. This leads to more reliable and maintainable code, as developers can be con-
fident that read-only data structures will not be inadvertently modified.
Dev Experience
Challenge:
Developers previously had limited control over type checking settings in TypeScript, mak-
ing it difficult to customize type checks to meet specific project needs. This lack of flex-
ibility could result in type checking that was either too strict or too lenient, reducing the
effectiveness of the type system.
Solution:
TypeScript 5.4 introduces new compiler options that give developers more control over
type checking settings. These options allow for greater customization of type checks,
so developers can tailor the type system to the specific needs of their projects.
{
"compilerOptions": {
"strictNullChecks": true,
"noImplicitAny": true,
"noImplicitThis": true,
"strictPropertyInitialization": true
}
}
Benefits:
New type checking options enhance customization and give developers more control over
how TypeScript enforces type checks. This flexibility leads to a more tailored and effective
type system, resulting in higher quality code and a better development experience.
With updates such as linkedSignal for reactive state management, hot module replace-
ment for faster development cycles, and the experimental resource API for streamlined
async operations, Angular continues to evolve as a modern framework.
From simplifying initializer setups to advancing language service capabilities, this ver-
sion release makes it easy for developers to build efficient, maintainable, and responsive
applications.
Challenge:
Managing the dependencies and changes between reactive signals in Angular can
be a challenging task in complex applications.
Although the existing reactive primitives, such as signal and computed, offer robust
solutions for handling reactivity, they lack mechanisms for directly coupling reactive
state changes with derived calculations that automatically reset when their source
changes.
Developers are often required to add extra boilerplate to achieve this functionality,
which increases the complexity of the code and reduces its maintainability.
Solution:
linkedSignal is a writable signal that links its value to a source signal and recalculates
itself based on a given computation function whenever the source signal changes.
• when the source signal changes, the value of linkedSignal automatically resets,
• the value of linkedSignal can be set manually using the set method, but it will
revert to the computed value when the source signal updates,
• the computation logic is located inside linkedSignal, keeping dependencies
clear and declarative while preserving all reactive programming features.
As shown in the example below, the set method of favoriteColorId allows the user
to specify a chosen color ID (see onFavoriteColorChange). When the available colors
are updated (see changeColorOptions), the value of favoriteColorId is recalculated.
If the selected color exists in the new list, the signal value remains unchanged; oth-
erwise, it defaults to null.
Expert Opinion:
The Signal APIs have significantly changed how Angular applications are built, making
them easier for new developers to learn, especially as the need for the RxJS library will
become optional.
However, in some situations, there were limitations that required developers to find
new patterns. For example, changing the value of signals that were not designed
to be changed (such as signal inputs) presented challenges.
The introduction of linkedSignal addresses this issue. It allows you to create a new signal
that reflects the state of another signal while still enabling you to modify the new sig-
nal's value independently. It ensures data consistency while keeping the original source
signal unchanged.
To further enhance linkedSignal, the Angular team added the ability to derive the sig-
nal's state conditionally using a computation function. It is particularly useful for sce-
narios where you need to reset the signal's value or provide a value based on certain
conditions.
~ Fanis Prodromou
Google Developer Expert
Challenge:
Solution:
The optional request parameter accepts the input signal that the asynchronous re-
source is associated with (in our example, it is fruitId, but it could just easily be a com-
puted signal consisting of multiple values).
We also define the loader function, with which we asynchronously download the data
(the function should return a promise). The created resource named fruitDetails allows
us to do the following, among other things:
• access the current value signal (which also returns undefined if the resource
is not available at the moment),
• access the status signal (one of: idle, error, loading, reloading, resolved, local),
• access extra signals like ‘isLoading’ or ‘error’,
• trigger the ‘loader’ function again (using the ‘reload’ method),
• update the local state of the resource (using the ‘update’ method).
What about RxJS Interop? Angular also provides an RxJS counterpart to the resource
method called rxResource. In this case, the loader method returns Observable, but all
other properties remain signals.
fruitDetails = rxResource({
request: this.fruitId,
loader: (params) => this.httpClient.get<Fruit>(`https://api.example.com/fruit/
${params.request}`)
})
Benefits:
The resource API streamlines the management of async operations in Angular by us-
ing an integrated, declarative approach. It reduces boilerplate, boosts maintainabili-
ty, and keeps async data seamlessly reactive with the app state. By exposing signals
for both value and status, resources make it easier to consistently handle loading, suc-
cess, and error states.
Before the introduction of the Resource API, developers often struggled to find effective
patterns to make HTTP requests based on changes to signal values.
Using effect: While useful in many situations, the effect was not designed to handle HTTP
requests. It could lead to issues like race conditions, where multiple requests might be
made simultaneously, and unpredictable application states.
Using RxJS subjects: Another approach involved using RxJS subjects to manage the sig-
nal values. However, this combined RxJS and Signals, increasing complexity and making
debugging more challenging.
The Resource API simplifies making HTTP requests based on signal changes.
Declarative requests: Define HTTP requests that automatically trigger when the source
signal updates.
Improved reliability: The API is designed to handle race conditions and prevent unpre-
dictable application states.
Built-in loading state: The Resource API provides a built-in loading state, making it easy
to display loading indicators to users without needing custom logic.
~ Fanis Prodromou
Google Developer Expert
Both linkedSignal and the resource API are the cherry on top of all the features the An-
gular team shipped in the last releases! linkedSignal enables the possibility of always
having a valid state based on another signal, and the resource API is truly impressive!
Using it, we can handle async requests exquisitely, giving the user the best feedback
possible and keeping the code base clean and easy to develop and maintain.
Challenge:
Managing side effects that depend on the DOM state in Angular can be challenging,
especially when those effects need to take place only after the DOM has been updated.
While Angular provides afterRender and afterNextRender to schedule post-render call-
backs, these APIs do not track signal dependencies, making them less suitable for sce-
narios where side effects need to be re-executed based on changes in reactive data.
Developers must often resort to manual tracking, which produces complex and less
maintainable code.
Solution:
counter = signal(0);
constructor() {
afterRenderEffect(() => {
console.log('after render effect', this.counter());
})
afterRender(() => {
console.log('after render', this.counter())
})
}
In this example, afterRender schedules its callback to run after every render cycle re-
gardless of any state changes. In contrast, afterRenderEffect runs its callback only
when the counter signal changes. This ensures that the effect is selectively executed,
based on relevant updates, cutting down on unnecessary operations and improving
application efficiency.
The afterRenderEffect function offers a powerful tool for managing post-render side effects
tied to reactive dependencies. By tracking dependencies and executing only on relevant
changes, it simplifies code, reduces boilerplate, and avoids unnecessary executions.
This makes applications more efficient and easier to maintain, especially in scenar-
ios with frequent state updates and DOM interactions. As an experimental feature,
afterRenderEffect lays the groundwork for more sophisticated reactive workflows
in the evolving Angular's ecosystem.
Challenge:
Reactive programming in Angular previously faced limitations in handling effects and sig-
nal updates. The effect() function restricted signal writes, adding additional complexity
in certain scenarios. At the same time its execution timing often caused i sues with pre-
mature or delayed updates. Similarly, the toSignal function lacked flexibility in value
comparison, forcing unnecessary updates due to a lack of custom equality logic.
Solution:
Angular 19 tackles these challenges with major updates to effect() and improve-
ments to toSignal.
Angular now supports custom equality functions in toSignal. Developers can set cus-
tom equality logic to trigger updates only when meaningful changes are detected,
improving performance.
Benefits:
These updates improve reactive programming in Angular. The revamped effect() func-
tion simplifies workflows by removing unnecessary restrictions and ensuring correct ex-
ecution timing.
In turn, The custom equality function in toSignal gives more control over updates, reduc-
ing unnecessary re-renders and boosting performance.. Together, these changes sim-
plify the code, make it easier to maintain, and improve the overall developer experience
in Angular apps.
Dev Experience
Challenge:
In previous versions of Angular, declaring variables within templates often meant using
the ngIf directive and @if with the as keyword. This method had its limitations, especial-
ly when dealing with falsy values (such as 0, empty strings, null, undefined, and false),
which would prevent content from rendering. For example:
Solution:
Angular introduces the @let block to simplify template logic by enabling variable dec-
larations directly in the template. This prevents issues with falsy values and improves
readability. The @let block lets developers declare variables directly in the template,
making it easier to handle complex conditions and asynchronous data.
With @let:
<div>
@let userName = (userName$ | async) ?? 'Guest';
<h1>Welcome, {{ userName }}</h1>
</div>
This code handles falsy values like empty strings by providing a default value ('Guest').
Benefits:
With the @let block, developers can declare variables within the template, simplifying
the overall logic. This improvement makes the code cleaner and more readable, espe-
cially when dealing with complex conditions and dynamic data. It also prevents falsy
value issues in ngIf, making sure content appears as expected.
Performance UX
Challenge:
Modern web applications demand both high performance and interactivity, espe-
cially for server-rendered content. Hydrating an entire application on the client side
can be resource-intensive, leading to slower load times and delayed interactivity.
Developers need a way to selectively hydrate parts of the application as needed to op-
timize resource usage and improve the user experience.
Solution:
Incremental Hydration works in tandem with defer blocks. To use it, developers can add
new hydration triggers to specific components:
These triggers give developers fine-grained control over hydration timing and behavior,
optimizing resources based on app needs and user actions.
Benefits:
In the same way, the flexibility provided by different triggers allows developers to tailor hy-
dration strategies to specific use cases, making applications more efficient and responsive.
While Server-Side Rendering (SSR) and Incremental Hydration offer significant perfor-
mance gains, they are not meant to replace Single-Page Applications (SPAs) completely.
These techniques benefit client-facing applications, especially when it's essential to min-
imize the time it takes for users to see and interact with the page for the first time.
~ Fanis Prodromou
Google Developer Expert
Incremental hydration has been missing for a while. Its predecessor, Server Side Render, was
a nightmare to implement, and it has impacted the decisions between React and Angular
for many teams in the past. Unfortunately, many chose React because it was already “ready.”
Performance UX
Challenge:
Solution:
Angular's experimental Server Route Configuration API lets developers set rendering
modes for routes flexibly and declaratively. Using this API, developers can optimize
the performance of their applications by choosing the most appropriate rendering
strategy for each route, such as server-side rendering (SSR), static site generation
(SSG), or client-side rendering (CSR).
Example configuration:
In this configuration:
• /login: Uses SSR to ensure that the latest data is rendered on every request.
• /fruits: Uses SSG to generate content at build time for faster loading.
• /*: Defaults to CSR for all other routes, optimizing for interactivity.
This example shows how the /fruit/:id route can dynamically generate static pag-
es for all available fruit IDs, guaranteeing optimized performance for frequently ac-
cessed resources.
Benefits:
The Server Route Configuration API makes it easier to manage hybrid rendering
in Angular applications. It reduces complexity and maintenance by allowing devel-
opers to declaratively define rendering modes for specific routes. The ability to dy-
namically resolve parameters for pre-rendered paths further increases flexibility,
making it easier to build high-performance and scalable applications.
Dev Experience
Challenge:
In Angular applications, sharing data between parent and child components routed
through a RouterOutlet often requires manual implementations, such as input bindings
or service-based state management. These methods can be tedious and prone to er-
rors, especially when dynamic updates are needed. Developers are looking for a more
efficient way to pass and update data.
Angular 19 introduces the routerOutletData input for RouterOutlet, simplifying the process
of sending data from parent components to child components routed through the outlet.
When routerOutletData is set, the data becomes accessible within the child components
using the ROUTER_OUTLET_DATA token. This token takes advantage of Angular's Signal
API. Changes in input data are dynamically reflected in child components, eliminating
the need for manual assignments or extra code.
Parent Component:
Child Component:
With this configuration, the parent component can dynamically update routerOutletDa-
ta, and the changes are automatically reflected in the child component. This increases
the flexibility of data sharing within routed components by eliminating the need for static
data mappings.
Benefits:
The routerOutletData input streamlines data communication between parent and child
components routed through RouterOutlet. Using Angular's reactive signaling type,
it makes dynamic updates possible, reducing the need for boilerplate code and manual
state synchronization.
Dev Experience
Challenge:
Configuring route navigation in Angular often requires the use of multiple inputs to Router-
Link, such as query parameters, fragment, and other options. When it comes to complex
navigation scenarios, this approach can become cumbersome and can cause errors.
Solution:
As of Angular version 18.1, the RouterLink directive now accepts anUrlTree object as its
input. By encapsulating route options like query parameters and paths into a single Url-
Tree object, this update streamlines the navigation process.
Example:
<a [routerLink]="homeUrlTree">Home</a>
It guarantees a consistent navigation setup and eliminates any confusion in route handling.
Benefits:
By allowing RouterLink to accept UrlTree objects, Angular gives developers a cleaner
and more flexible way to define navigation logic. This improvement simplifies code,
enhances readability, and keeps navigation configurations in one place. Additionally,
the clear error messages help developers avoid common pitfalls, making applica-
tions more robust and easier to maintain.
Challenge:
Solution:
Angular now allows developers to globally set a default query parameter handling strat-
egy in the provideRouter() configuration. The result is the elimination of repetitive per-
route configurations, which streamlines navigation logic and improves maintainability.
Example:
This flexibility ensures that query parameter handling meets application-specific require-
ments, reducing boilerplate and potential inconsistencies.
Benefits:
With a global query parameter handling strategy, Angular reduces repetitive code, simpli-
fies navigation, and ensures consistency across the app. This feature increases the pro-
ductivity of the developer while maintaining the flexibility for advanced use cases.
Challenge:
The legacy approach to Angular components often relies on explicit module declara-
tions, which can add complexity and create barriers for new developers. Standalone
components were introduced in v14, but not by default, creating inconsistencies
and additional setup for developers wishing to use them.
Solution:
With Angular v19, standalone: true becomes the default for components, directives,
and pipes. Angular becomes more intuitive and accessible with this change, as ex-
plicit module declarations are no longer needed in most cases.
Example:
@Component({
imports: [],
selector: 'home',
template: './home-component.html'
// standalone in Angular 19!
})
export class HomeComponent { }
For existing projects, an automated migration during the ng update will adjust standalone
flag settings as needed, ensuring compatibility and facilitating a smooth transition.
Benefits:
Making standalone components the default makes Angular's mental model simpler,
especially for new developers. In keeping with Angular's goal of streamlining devel-
opment workflows, this enhancement better supports features such as lazy loading
and component composition, and reduces boilerplate. Automated migration tools
make sure that existing projects can seamlessly adopt the new defaults, minimizing
disruption while providing a modern development experience.
Challenge:
Keeping Angular projects up to date with the latest features and best practices
can be a daunting task. Especially for large or legacy codebases, manually refactoring
code to take advantage of new APIs, improve performance, or simplify the architecture
is a significant maintenance burden.
Solution:
ng g @angular/core:inject
This migration simplifies the code by replacing the constructor syntax with a more
streamlined approach:
// before
constructor(private productService: ProductService) {}
// after
private productService = inject(ProductService);
After migration, you may encounter compilation issues, especially in tests that di-
rectly create instances of injectables. The migration utility provides several options
to customize the process, such as how to handle abstract classes, how to maintain
backward-compatible constructors, and how to manage nullable settings to ensure
a smooth transition without breaking existing code.
ng g @angular/core:route-lazy-loading
// before
{
path: 'products',
component: ProductsComponent
}
// after
{
path: 'products',
loadComponent: () => import('./products.component').then(m => m.ProductsComponent)
}
The migrations for signal inputs, outputs, and queries make Angular more responsive
by converting traditional input properties, event outputs, and query fields to their mod-
ern, signal-based counterparts. This improves code efficiency and maintainability.
ng generate @angular/core:signal-input-migration
ng generate @angular/core:output-migration
ng generate @angular/core:signal-queries-migration
Benefits:
Challenge:
Using Angular's standalone components, directives, and pipes consistently can be hard
in projects migrating from older versions or where developers are unfamiliar with stan-
dalone conventions. Without enforcement, non-standalone components can uninten-
tionally proliferate, leading to mixed patterns and increased complexity in maintaining
the codebase.
Solution:
Configuration Example:
{
"angularCompilerOptions": {
"strictStandalone": true
}
}
Enabling this flag ensures that only standalone entities are used, reinforcing Angular’s
evolution toward a modular and simplified framework. Violations will result in a com-
piler error:
Benefits:
Dev Experience
Challenge:
• provideAppInitializer
• provideEnvironmentInitializer
• providePlatformInitializer
These functions serve as syntactic sugar that simplifies the setup process for application,
environment, and platform-level initializers. By replacing traditional tokens, they provide
a cleaner, more readable, and more intuitive way to configure initialization logic.
Example:
In addition, Angular v19 includes a migration tool to help developers convert existing
initializers to this new format. This automation minimizes manual effort and facilitates
a smooth adoption of the updated approach.
Benefits:
New initializer provider features improve the readability and maintainability of initial-
izer setups by reducing boilerplate and simplifying configuration.
Challenge:
Solution:
Angular’s Extended Diagnostics provide real-time code checks that go beyond stand-
ard errors and warnings to identify potential problems and enforce best practices.
In Angular 19, two new diagnostics extend this capability:
Uninvoked Functions: Flags instances where a function is used in an event binding but
isn’t called due to missing parentheses in the template. This helps ensure that func-
tions in event bindings are executed correctly, preventing runtime errors.
Example:
Detects standalone components, directives, or pipes that are imported but not used
in the application. This maintains a clean codebase by prompting developers to re-
move unused imports.
// Incorrect
@Component({
imports: [UnusedComponent],
template: '<div>hello</div>'
})
export class MyComponent {}
// Correct
@Component({
imports: [],
template: '<div>hello</div>'
})
export class MyComponent {}
We encourage you to explore and test other Angular diagnostics documented in the offi-
cial Angular documentation to further refine your projects and uphold strong code quality.
Benefits:
These new diagnostics improve the quality of your code by catching subtle prob-
lems early in the development process, reducing technical debt and run-time errors.
They ensure adherence to Angular’s best practices, resulting in cleaner, more main-
tainable applications.
Challenge:
Developers often face workflow disruptions when making changes to styles or tem-
plates, because the Angular CLI traditionally requires a full page refresh for updates
to take effect. This process not only slows down the development cycle, but also results
in the loss of application state, breaking the flow of iterative design and debugging.
Solution:
Angular v19 introduces built-in support for Hot Module Replacement (HMR) for styles
and experimental support for template HMR, greatly improving the development expe-
The HMR for styles is enabled by default. Simply modify the styles of a component, save
the changes, and see them immediately reflected in the browser without reloading
the page.
NG_HMR_TEMPLATES=1 ng serve
ng serve --no-hmr
Benefits:
Hot module replacement updates styles and templates in real time, cutting develop-
ment time without losing application state. This feature increases developer produc-
tivity by maintaining an uninterrupted workflow, speeding up iterations, and promoting
a more efficient debugging process.
Challenge:
Angular developers rely heavily on the Angular Language Service (ALS) to guarantee
productive and bug-free development. However, keeping ALS up to date with the latest
features and supporting advanced functionalities has been a challenge. Developers
often lack auto-completion for unimported directives, and may struggle with unused
imports or migrating to newer APIs like signals.
The latest updates to the Angular Language Service bring a host of new features to en-
hance the development experience:
Support for Signal Migrations: It provides refactoring tools for migrating @Input prop-
erties to signal inputs and updating queries to signal-based APIs, reducing the effort
required to adopt Angular’s modern features.
Benefits:
Angular v18.1 introduces support for TypeScript 5.5, while Angular v19.0 extends com-
patibility to TypeScript 5.6 and removes support for versions prior to 5.5.
TypeScript can now narrow expressions such as obj[key] when both obj and key are ac-
tually constants.
Typescript will throw an error when truthy or nullish checks always evaluate to true
(which is correct in terms of JS syntax, but usually implies some logical error).
if(/^[a-z]+$/) {
/* missing .test(value) call, regex itself is always truthy */
}
if (x => 0) {
/* "x => 0" is an arrow function, always truthy */
}
Isolated modules
Angular 18.2 introduced support for TypeScript’s isolatedModules, which can improve
production build times by up to 10% by allowing code transpilation through the bundle.
This optimizes TypeScript constructs and reduces Babel-based passes.
"compilerOptions": {
"isolatedModules": true
}
It applies a few extra restrictions, such as no cross-file type inference, allowing only
const enums to be exported, and forcing explicit declarations of type-only exports (us-
ing import type syntax).
Without isolatedModules, full type checking is performed for the entire codebase during
the compilation process. In contrast, with isolatedModules enabled, each file is com-
piled independently, and certain cross-file type analysis is skipped.
We have a lot of features that are currently in the experimental phase and will sooner or later
become stable. In addition, let's take a look at some extra areas that seem very promising:
Signal Forms
Angular is exploring the use of signals in form management through the experimen-
tal Signal Forms API. This approach integrates reactive state management directly into
forms, enabling dynamic synchronization between form fields and templates. Signal
Forms aims to reduce boilerplate code, simplify cross-field validations, and enhance
flexibility by leveraging Angular’s signals. Although in its early stages, this feature shows
promise in streamlining complex form handling while aligning with Angular’s modern
development paradigm.
Early concepts for the potential API of this feature are already emerging, offering a glimpse
into how developers might interact with it in future releases:
The Signal Forms might end the long-standing “battle” between Reactive Forms and Tem-
plate-Driven Forms in Angular. Many developers strongly prefer one approach over
the other. Both have their level of difficulty, which often increases when you need to divide
a form into smaller parts.
Working with Signals in forms also presented some challenges. In Reactive Forms, devel-
opers had to find patterns to integrate Signals. Converting `.valueChanges` to a Signal
using `toSignal` was a common step, but developers had to figure out how to use other
Signal features like `effect` within the form logic. While this seems like a nice solution/pat-
tern, there is no single way to do this, leading to inconsistent approaches across projects.
I believe Signal Forms will significantly improve the developer experience (DX). They will
make working with Signals within forms much easier and simplify the process of breaking
down large forms into smaller, more manageable components.
~ Fanis Prodromou
Google Developer Expert
Reactive Forms are still the best solution for most cases, but there are specific scenar-
ios where you need more control in the form, and a Signal form is open to this solu-
tion. In my opinion, this solution is a bit verbose in the steps to follow (create a signal
for every field and create the form to link every signal), but yes, you can have more
control and simplify some controls or checks in the form.
It will play a large part in the Angular Form world.
Zoneless Angular
Angular is actively advancing its zoneless capabilities to enhance performance and de-
veloper experience. In version 18, experimental support for zoneless change detection was
introduced, allowing developers to build applications without relying on Zone.js, thereby
improving performance and debugging. Version 19 expanded this support to server-side
rendering and provided tools to facilitate the creation of zoneless projects. The Angular
team is currently focusing on addressing remaining edge cases and gathering feed-
back to ensure a seamless transition before moving this feature to developer preview.
Developers can anticipate further refinements and broader adoption of zoneless change
detection in upcoming releases.
bootstrapApplication(App, {
providers: [
provideExperimentalZonelessChangeDetection()
]
});
In the future Angular SSR technique will be easier to implement, it will not require much
configuration and will provide hydration so that Angular apps will be able to resume
at some point.
~ Aristeidis Bampakos
Google Developer Expert
Overall
The future of the Angular framework is focused on embracing modern web develop-
ment paradigms, prioritizing performance, and simplifying developer workflows. Key ef-
forts include advancing reactive state management with signals, enhancing server-side
rendering capabilities through streaming and hydration, and reducing boilerplate with
features like selectorless components. Angular is committed to evolving as a versa-
tile and developer-friendly framework, integrating community feedback and adapting
to emerging trends in web technology.
~ Stefan Haas
Nx Champion
In this context, a rational approach is derived from the observed behavior of the ma-
jority of clients I have encountered. Within the organizations I have collaborated with,
those employing Angular-based applications exhibit a certain reluctance when it comes
to embracing the latest Angular versions. Their hesitancy arises from their search
for compelling reasons to justify such upgrades. At the core of this deliberation lies
the end consumer, the user, and their user experience.
For instance, take the case of Angular 15's Standalone API. Its implementation may not
manifest any discernible impact on the end user; it could be argued that its primary
effects are confined to enhancing the developer experience, and even this judgment
is inherently subjective. It's important to acknowledge the formidable challenge posed
by the task of updating huge applications that lack comprehensive test coverage. The
absence of robust testing engenders substantial risks, rendering the application more
susceptible to vulnerability in the face of such alterations.
~ Artur Androsovych
Angular Expert
~ Dmytro Mezhenskyi
Google Developer Expert
I know with all the exciting new changes coming out, you may be excited to embrace
the latest and greatest. And, pragmatically, I think it's a great way to learn for personal
projects or small isolated projects, but when it comes to larger projects involving a lot
of developers, I'd urge you to hold back for 2 things: For your team to feel comfortable
discussing the change and taking on the work, and for good documentation and best
practices to be established. Some of the new concepts are just the beginning of bigger
things and we may find reasons to tweak, iterate, or pivot. No need to chase shiny as the
goal. On the other hand, Angular has also released security updates, enhancements,
and updating their dependencies to ensure the Angular projects we create are secure
in recent versions. It just doesn't get all the attention some of the bigger changes get.
It's vital to update Angular and dependencies following security guidelines and when
enhanced security features are released.
~ J. Alisa Duncan
Google Developer Expert
If your current project is based on Angular 10 or an earlier version, it may start to feel
outdated within the rapidly evolving framework landscape. The community
is continually striving to stay up-to-date, and you'll often find that answers
on platforms like StackOverflow and other websites revolve around the latest Angular
frameworks.
~ Balram Chavan
Google Developer Expert
I think it's more important than ever to stay up-to-date and try to adopt every new major
version of the framework as it is released. That way, you won't feel overwhelmed in a year
or two, making it even more difficult to catch up.
~ Alain Chautard
Google Developer Expert
Tooling is also essential. Built tools are becoming faster and better, and often tend to de-
pend on a modern codebase.
Another issue with an outdated codebase is the difficulty of onboarding new developers.
They might not have heard about NgModules, have been trained to work with Signals,
and struggle with OnChanges, @Input decorators, etc.
Most companies will find themselves in the middle. This means trying to make use of An-
gular's new features when they implement a new feature themselves or when refactoring
parts of their app. That would be an incremental migration with different layers of "Angu-
lar generations." It's a compromise, but it's always better than sticking to the old waysor
doing a big-bang migration.
~ Rainer Hahnekamp
Google Developer Expert
You have to be up-to-date with all the frameworks that you want to choose.
Sometimes it's difficult to explain this to the business, but with a few small steps you can
make it happen.
What we can do in my team is basically use the Dependabot. Within a minor release
or a patch, we have a CI, and the Dependabot will try to update the library. And if the
CI passes and it's green, it's an auto-merge in the codebase. This is fantastic. When you
have a major update, you need to schedule it, as it's normal to spend some time upgrad-
ing. However, if you spend three days upgrading to the major version, you'll benefit from
all the code-based updates and can utilize the latest features. This not only helps your
current team members but also makes it easier to integrate new developers. Conversely,
if you lose the ability to upgrade to the latest version, you risk losing valuable talent from
your team.
.
~ Luca del Puppo
Google Developer Expert
~ Dmytro Mezhenskyi
Google Developer Expert
This question is somewhat complex to answer. If you're just starting to learn Angular now,
the process is considerably easier than it was a few years ago. This is because most of the
popular web frameworks have embraced TypeScript, and Angular is not the only framework
advocating for a typed approach to web development. Notably, features like standalone com-
ponents, simplified routing APIs, the introduction of new control flow syntax, and improved error
reporting have made it more accessible for newcomers to dive into the Angular ecosystem.
In addition, the Angular documentation has grown significantly, offering a wealth of tutori-
als and advanced concepts. There are official cheat sheets, resources to address common
errors and their solutions, an open Discord channel for developers to connect, and a range
of Google-sponsored and community-driven events that enable developers to network
and learn from one another.
However, it's worth noting that many experienced developers have expressed concerns
about the rapid pace of change and the introduction of new features. This sometimes re-
quires them to revisit and potentially rewrite their existing projects, as well as continually
learn and adapt to stay current in the Angular landscape.
~ Balram Chavan
Google Developer Expert
I have been able to collect a lot of feedback from my students over the last few years.
RxJs and the app structure with the modules were often described as too complicated.
Little by little, we are eliminating these pain points
.
~ David Muellerchen
Google Developer Expert
The learning curve will be flat for new beginners because they won’t have to go through
the same pains that experienced developers went through.
When experienced Angular developers learned the old version of Angular, they had
to know NgModule and import it to AppModule before using Angular components.
To write reactive code, they used Subject to store the state, subscribed the Subject to re-
solve the Observable, and finally unsubscribed the subscription to avoid a memory leak.
These are a few examples of how Angular intimidated beginners in the old days.
Fast forward to 2023, the difficulties of building Angular applications are significantly
lower. We can learn standalone components and use them as the building blocks
~ Connie Leung
Google Developer Expert
Wow, I feel bad for new Angular developers. They must feel like there's quite a dichotomy.
I think the difficulty in learning changes from the learner's past experience. If they
are already familiar with the web frameworks out there, they may prefer the new
changes, and if they are .NET devs, they may prefer the prior form of Angular. New devs
who have to learn how to maintain legacy Angular projects while simultaneously learning
new changes for new work are the ones I feel the most for. That said, while learning can
cause discomfort for all of us, I'm looking forward to these changes, how the framework
grows, and seeing all the cool things we can do with these features.
~ J. Alisa Duncan
Google Developer Expert
Angular’s learning curve used to be steep. Newcomers had to learn how to handle
the modules, how to work with the structural directives, how to extract the required info
from the error stack trace, and learn how to master RxJS.
The latest features and improvements made these hurdles easy to overcome.
The modules are no longer needed as an application can be standalone.
The structural directives have been replaced with the new control flow and as a result
the developer experience has been improved a lot!
The error stack trace provides useful information and it's easier to understand where
an error is coming from.
Last but not least, the presence of signals means that mastering RxJS is no longer
a necessity.
~ Fanis Prodromou
Google Developer Expert
~ Aristeidis Bampakos
Google Developer Expert
The Angular team is highly responsive to community feedback, and their recent additions
reflect their commitment to improving the framework. Features like standalone
components, the inject() function for dependency injection, functional guard routes,
and the introduction of new control flow syntax for directives like ngFor and ngIf
demonstrate the team's endeavor to incorporate the best practices from other popular
frameworks such as React, Svelte, and Vue. Furthermore, the Angular team is investing
more effort into areas like Server-Side Rendering, Hydration, SEO optimization,
integrating ESBuild, engaging in discussions around Microfrontends, and more.
These initiatives clearly indicate that there are exciting developments on the horizon
for Angular.
~ Balram Chavan,
Google Developer Expert
There is a brighter future for Angular with all the great provided features
and improvements since v14 to v17. It’s the renaissance of Angular. These up-
dates bring significant improvements and simplifications, such as standalone compo-
nents, the removal of the need for modules, and the introduction of functional guards.
The latest versions introduce powerful features, including built-in control flow, en-
hanced performance in v17, and deferred loading, which allows you to achieve a lot with
minimal code. The Angular team has hinted at a big surprise in v17, I won't spoil it (ha-
hah), but this surprise will for sure make learning Angular easier and greatly enhance the
learning experience.
~ Fatima Amzil
Google Developer Expert
It is the best time to be an Angular developer, and the Angular team works tirelessly
to include new and exciting features in each release. Angular 17 has not come out yet,
and major Angular podcasters have already scheduled meetings with Angular team
members to discuss Angular 18 and beyond.
~ Connie Leung
Google Developer Expert
~ Alain Chautard
Google Developer Expert
When you need to develop a reusable component, you can use different techniques
and different angular features. One of them is the content projection where you can have
either a single slot or multiple slots.
There are many cases where you need to have default content since you are not always
sure that the consumer of that component will project content to that slot. Content pro-
jection with fallback content makes things much easier!
~ Fanis Prodromou
Google Developer Expert
Partial Hydration. It’s the feature that will directly affect our app users experience.
~ Enea Jahollari
Google Developer Expert
If you’d like to upgrade the Angular version in your project but don’t know where to start,
or if you have any questions about Angular or its features, we would be happy to help.
Book a 30-minute meeting with an ebook author to discuss your challenges or just
contact us by e-mail: [email protected]
Our team at House of Angular is passionate about Angular. We have worked with the
framework since its release and will happily share our knowledge and experience with
you through audits or consulting.
An audit of the code can help you identify vulnerabilities within the code and figure
out how to deal with them. It will also help you determine how to leverage Angular’s
new features in your project effectively. Our experienced Angular Developers will give
you recommendations in four key areas:
• Code quality
• Functionality
• Architecture
• Performance
If you’d like to find out whether the audit or consulting will address the challenges in
your Angular project, just fill out the contact form. We will schedule the first 30-minute
talk just to discuss your project.
Contact us
WeareDevelopers
WaysConf
WaysConf, the largest event for creators of digital products
in Central and Eastern Europe, is set to take place on Sep-
tember 17-18, 2025. WaysConf has evolved to embrace pro-
fessionals from diverse backgrounds, including researchers,
designers, developers, and managers.
About authors
Main Authors
Mateusz Dobrowolski
Angular Developer at House of Angular. Key Contributor to Angular.love. He takes an
active part in the angular.love community, writing expert articles, and sharing his
knowledge at Angular meetups.
If you found this e-book useful (or not) please, let us know. Send your feedack to the
author: @m-dobrowolski
Mateusz Stefańczyk
Angular Team Leader a House of Angular. Key Contributor to Angular.love. For 7 years,
he has been developing web applications with Angular. He has performed dozens of
audits for Angular projects worldwide. Mateusz actively participates in the angular.love
community, writing expert articles, and sharing his knowledge at Angular meetups in
Poland, Norway, Germany, and the UK.
If you found this e-book useful (or not) please, let us know. Send your feedack to the
author: @m-stefanczyk
Special thanks to
Krzysztof Skorupka
Angular Team Leader & Architect at House of Angular. Key Contributor at Angular.love
community, blogger, and speaker.
Przemysław Łęczycki
Angular Team Leader at House of Angular. Expert at Angular.love community, blogger,
and speaker.
Dominik Donoch
Angular Developer at House of Angular. Key Contributor Angular.love.
Invited experts
Fatima Amzil
Fatima is a cross-functional frontend technical leader and an ex-
pert in Angular. Outside of her professional life, she contributes as a tech-
nical writer on Medium, mentor at MyJobGlasses, and an Angular GDE.
Artur Androsovych
Artur is an OSS core developer of various projects as NGXS, NG-ZORRO, single-spa, ng-
neat (until-destroy code owner), and RxAngular. He was a Google Developer Expert
in Angular in 2023. He focuses on runtime performance and has taught teams about
Angular internals for the past few years.
Aristeidis Bampakos
Aristeidis is an Angular GDE who works as Web Development Team Lead at Plex-Earth.
He is an award-winning author of Learning Angular and Angular Projects books. Cur-
rently, he is leading the effort of making Angular accessible to the Greek develop-
ment community by maintaining the Greek translation of the official Angular docu-
mentation.
Alain Chautard
Alain is a Google Developer Expert in Angular, and Google Maps. His daily mission is to
help development teams adopt Angular and build at scale with the framework. He has
taught Angular on all six continents!
Balram Chavan
Balram is an Architect specializing in designing and creating scalable, secure solutions
for various domains. His expertise spans the cloud, AI and web development land-
scape. As the author of an Angular framework book, he excels as a team player, an
effective communicator, and a mentor.
J. Alisa Duncan
Alisa is a Senior Developer Advocate at Okta, full-stack developer, content creator,
conference speaker, Pluralsight author, and community builder who loves the thrill of
learning new things. She is a Google Developer Expert in Angular, a Women Techmaker
Ambassador, a ngGirls core team member, and a volunteer at community events sup-
porting underrepresented groups entering tech.
Rainer Hahnekamp
Rainer is a Google Developer Expert, working as a trainer and consultant in the expert
network of Angular Architects. In addition, he offers a weekly brief overview of relevant
events in the Angular ecosystem on YouTube through ng-news.
Enea Jahollari
Enea is a Google Developer Expert for Angular, Consultant, Trainer & Senior Software
Engineer who builds, audits and optimizes web applications @ Push-Based.io. He loves
open source and contributes to it by writing code, content, and tweets! Loves hyping
Angular in his free time.
Connie Leung
Google Developer Expert for Angular. Software Architect at Diginex, blogger
and youtube content creator.
Dmytro Mezhenskyi
Dmytro Mezhenskyi is the founder of the Decoded Frontend YouTube channel, where
he shares his knowledge about the Angular framework. As an author, he has created a
series of advanced video courses focusing on Angular and GraphQL. With over 10 years
of experience in frontend development, Dmytro has been recognized as a Google De-
veloper Expert in Angular and a Microsoft MVP in Web Development.
David Muellerchen
Better known as WebDave, David has been an integral part of the Angular community
since 2014. He is a Google Developer Expert, an Angular consultant and trainer, and
a frequent speaker at meetups and conferences. He also organizes weekly Angular
livestreams and the Hamburg Angular Meetup.
Fanis Prodromou
Fanis is a Senior Front-End Developer, Google Developer Expert for Angular, and Con-
tent Creator with a passion for sharing his knowledge and helping other developers.
He has developed vast experience in code quality, application architecture, and appli-
cation performance. Fanis is also a strong advocate for staying up-to-date on the lat-
est technologies, and regularly attends conferences and meetups to learn from other
experts.
Marko Stanimirović
Marko is a Principal Frontend Engineer at Swiss Marketplace Group. He is also a core
member of the NgRx and AnalogJS teams, a Google Developer Expert in Angular, and
an organizer of the Angular Belgrade group.
Their goal is to craft the finest frontend solutions using Angular, while also imparting their
knowledge and expertise to other users of this framework.
The company is actively involved in nurturing the Angular community. They support key
Angular libraries like ngrx, NGXS, and ngneat. Additionally, their team members contribute
to open-source Angular projects and spread their expertise through writing articles and
giving talks at European meetups.
House of Angular has been recognized for their contributions with the Angular Hero of
Community 2021 award.
Angular developers can find expert insights and expand their Angular knowledge by
reading the angular.love blog, attending meetups with talks from experts, and following
the community platform’s social media pages.