Everyone talks about the big new features in every Angular version, like Standalone Components, Signals, or Control Flow Syntax. But did you know that Angular also has many hidden gems? These features are not very popular, but they can make your code cleaner, faster, and easier to maintain.
In this article, I'll list 10 useful but not well-known Angular features that you should start using in your projects! I will also mention which Angular version introduced them, so you know if you can use them in your project.
Let's go!
1 - inject() Function (Angular 14+)
This is one of the most powerful hidden features in Angular. Before Angular 14, we always used dependency injection inside constructors. But now, inject() lets you get dependencies without a constructor, making code simpler and more flexible.
Example:
import { inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
const http = inject(HttpClient);
=> Why use it?
- Works outside components, like in functions or standalone services.
- Makes unit testing easier.
2 - provideHttpClient() (Angular 15+)
Instead of importing HttpClientModule in AppModule, you can now provide the HTTP client directly in main.ts.
Example:
import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient } from '@angular/common/http';
import { AppComponent } from './app.component';
bootstrapApplication(AppComponent, {
providers: [provideHttpClient()]
});
=> Why use it?
- Reduces boilerplate code.
- Works great with standalone components.
3 - NgOptimizedImage Directive (Angular 15+)
Handling images correctly is important for performance and SEO. NgOptimizedImage makes it easy to lazy-load and optimize images automatically.
Example:
<img ngSrc="image.jpg" width="800" height="600" loading="lazy">
=> Why use it?
- Lazy-loads images automatically.
- Ensures better Core Web Vitals without extra effort.
4 - Functional Guards and Resolvers (Angular 15+)
Now, you can write guards and resolvers as simple functions instead of services.
Example:
export const authGuard = () => inject(AuthService).isLoggedIn();
=> Why use it?
- No need for injectable services.
- Less boilerplate, making code simpler.
5 - model() Function (Angular 17+)
A new, cleaner way to bind form inputs without ngModel or ReactiveForms.
Example:
import { signal } from '@angular/core';
const name = signal('Angular');
<input type="text" [model]="name">
<p>Hello, {{ name() }}!</p>
=> Why use it?
- Works without FormsModule, making apps lighter.
- Uses Signals, making it reactive and fast.
6 - DestroyRef (Angular 16+)
A better way to clean up subscriptions and event listeners without manually using ngOnDestroy()
.
Example:
import { Component, DestroyRef, inject } from '@angular/core';
import { interval, takeUntil } from 'rxjs';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@Component({
selector: 'app-example',
template: `<p>Check the console for updates</p>`,
})
export class ExampleComponent {
private destroyRef = inject(DestroyRef);
constructor() {
interval(1000)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => console.log('Still running...'));
}
}
=> Why use it?
- No need for
ngOnDestroy()
to unsubscribe. - Prevents memory leaks automatically.
- Works great with RxJS and event listeners.
7 - provideRouter() Function (Angular 14+)
A cleaner way to define routes without RouterModule.
Example:
import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter } from '@angular/router';
import { AppComponent } from './app.component';
import { HomeComponent } from './home.component';
bootstrapApplication(AppComponent, {
providers: [provideRouter([{ path: '', component: HomeComponent }])]
});
=> Why use it?
- Works great for standalone components.
- No need to import RouterModule everywhere.
8 - Required Inputs in Components (Angular 16+)
Now you can mark inputs as required to prevent missing data.
Example:
@Component({
selector: 'app-card',
template: `<h2>{{ title }}</h2>`
})
export class CardComponent {
@Input({ required: true }) title!: string;
}
=> Why use it?
- Prevents runtime errors when an input is missing.
- Makes components more predictable.
9 - toSignal() for Converting Observables (Angular 16+)
Easily convert an Observable to a Signal for better reactivity.
Example:
import { toSignal } from '@angular/core/rxjs-interop';
import { interval } from 'rxjs';
const count = toSignal(interval(1000));
console.log(count()); // Updates every second
=> Why use it?
- Makes RxJS and Signals work together smoothly.
- Removes the need for async pipe in templates.
10 -View Transitions API (Angular 17+)
A simple way to add smooth page animations when navigating between routes.
Example:
import { provideRouter, withViewTransitions } from '@angular/router';
bootstrapApplication(AppComponent, {
providers: [provideRouter(routes, withViewTransitions())]
});
=> Why use it?
- Creates beautiful animations without extra CSS or libraries.
- Improves user experience for navigation.
Final Thoughts
These hidden gems are not as famous as Standalone Components or Signals, but they can make your Angular projects faster, cleaner, and easier to maintain!
Which of these features surprised you the most? Let me know in the comments!
Top comments (0)