Discover what changed!
Introduction
Angular 14 was recently released with a bunch of exciting features. And today, I'll present them to you. They are:
- Standalone components
- Route Providers
- ENVIRONMENT_INITIALIZER
- Typed Forms
- The
inject()
Function - Setting the Page title from the route
- Autocomplete in the Angular CLI
- Optional injectors in Embedded Views
So let's get started!
Standalone components
For most people, the most significant change in this version is the possibility of creating componentswithout@NgModule
s! Yeah, you got that right.
Before Angular 14
If you are a bit lost, let me show you a folder structure from a classic Angular component:
home|--home.component.html|--home.component.css|--home.component.ts|--home.module.ts;
There, we have an.html
file for the template, a.css
file for the styles, a.ts
file for the component, and another.ts
file for the@NgModule
. This last file imports the dependencies of our component, declares the component, and can also define some providers.
A new possibility with Angular 14
In Angular 14, we can do all that directly in the component, without needing an@NgModule
.
home|--home.component.html|--home.component.css|--home.component.ts;
To do that, we just need to set thestandalone
property in our component totrue
.
@Component({selector:'app-home',templateUrl:'./home.component.html',styleUrls:['./home.component.scss'],standalone:true,})
Be aware!
Be aware:
- Standalone components are notthe new way of declaring components! They areanother way of declaring components. The classic way of defining
@NgModule
s will not be deprecated.
Well, I can't really promise that it won't be deprecated. But yeah, so far, there are no intentions of deprecating
@NgModule
s.
As a matter of fact. I will still use@NgModule
s instead of standalone components because I like the isolation that@NgModule
s provides.
- Don’t migrate your entire application to standalone components yet!Standalone components are very recent, and it will take us a while to create conventions and define best practices. I recommend waiting a bit longer before jumping ship.
Route Providers
But hey, if we drop the@NgModule
and use standalone components, how can we set provider by route, like we used to do with@NgModule
s?
To address that, Angular added route providers. So, basically, route definitions now have a property calledproviders
. Allowing us to provide values only to the modules and components rendered by that route.
constNAME=newInjectionToken<string>('token');exportconstroutes:Routes=[{path:'',component:HomeComponent,providers:[{provide:NAME,useValue:'foo'}]}];
ENVIRONMENT_INITIALIZER
Another thing we used to do withNgModule
s was run a setup script when a lazy loaded module was initialized. In other words, theconstructor
of a lazy loaded module would only run when the module was initialized, and some developers take advantage of that to run some kind of setup.
exportclassHomeModule{constructor(){console.log('You can run something here');}}
How can we do that with standalone components? The solution is to use theENVIRONMENT_INITIALIZER
token.
constroutes:Routes=[{path:'',pathMatch:'full',component:HomeComponentproviders:[{provide:ENVIRONMENT_INITIALIZER,multi:true,useValue:()=>console.log("You can run something right here too")}]}]
This token allows us to provide a setup function that will run before the environment is initialized.
If we want it to run when we navigate to a route, we can provide this token using route providers.
This has the same effect as our previous solution usingNgModule
constructor
s and has the added benefit of being more explicit.
Typed Forms
Another long-awaited feature of Angular 14 is typed forms.
Before version 14, form values were typed asany
. This means that we lose all the awesome type-safety of TypeScript.
constcontrol=newFormControl(""),control.value//=> control.value: any
By the way, there is a type-safe way of saying that you don't know the type of something. If you're interested in that, check out this one minute video explaining the differences between
any
andunknown
.
Anyway, we don't have that problem anymore. Because Angular 14 has strict types for forms. So if aFormControl
deals with astring
, the value will be typed as astring
instead ofany
.
constcontrol=newFormControl(""),control.value//=> control.value: string | null
Theinject()
Function
Now, this is the most interesting feature to me.
Angular 14 introduces theinject()
function. And it looks very much like React hooks. It gives us a universe of possibilities to reuse our code, the most relevant being that we can now create reusable functions which use dependency injection internally.
exportfunctiongetPosts(){consthttp=inject(HttpClient);returnhttp.get('/api/getPosts');}exportclassHomeComponent{readonlyposts=getPosts();}
If you're as interested n functional programming as I am, you know that means a lot! But as Uncle Ben has once said:
"With great power comes great responsibility”
This creates implicit dependencies in your functions. I expect my function dependencies to be explicitly declared in the function arguments. So if I see a function with no arguments, I imagine it to have no dependencies. But now, we can create functions that seem pure but inject a lot of dependencies internally, making them harder to test and more coupled to the Angular framework.
A good solution is to follow the same convention that we have on React, which is to prefix those functions with"use"
. So that way, you can easily identify functions that useinject()
internally.
exportfunctionuseGetPosts(){consthttp=inject(HttpClient);returnhttp.get('/api/getPosts');}exportclassHomeComponent{readonlyposts=useGetPosts();}
Set Page title from the route
One common task in web applications is changing the page title on each route.
In Angular, this used to be a very manual process, but now, we can simply define the page title in the route definition.
exportconstroutes:Routes=[{path:'',component:HomeComponent,title:'Home',pathMatch:'full'}];
But I know what you're thinking:
"Lucas, I can't set the title in the route definition because my title is not static, it depends on something I get from my API".
Don't worry. Angular 14 got you covered.
If you need to customize the title dynamically, you can do so by extending the TitleStrategy
class from the @angular/router
, and providing your new, custom title strategy instead of the default one.
@Injectable({providedIn:'root'})exportclassPageTitleStrategyextendsTitleStrategy{constructor(@Inject(Title)privatetitle:Title){super();}overrideupdateTitle(routerState:RouterStateSnapshot){consttitle=this.buildTitle(routerState);if(title!==undefined){this.title.setTitle(`CompanyName |${title}`);}else{this.title.setTitle(`CompanyName | Page without title`);}}}exportconstroutes:Routes=[{path:'',component:HomeComponent,title:'Home',pathMatch:'full'}];bootstrapApplication(AppComponent,{providers:[importProvidersFrom(RouterModule.forRoot(routes)),{provide:TitleStrategy,useClass:PageTitleStrategy}]});
Angular CLI Autocomplete
Another nice little thing is that we now have autocomplete in the Angular CLI.
Just typeng
on your terminal and pressTAB
to let the Angular CLI either autocomplete your command or give you some help.
>ngse//=> If you press TAB here, the CLI will complete>ngserve
>ng//=> If you press TAB here, the CLI will show a list of commands>ngadd--Addssupportforanexternallibrarytoyourproject.analytics--ConfiguresthegatheringofAngularCLIusagemetrics.build--CompilesanAngularapplicationorlibraryintoanoutpu...cache--Configurepersistentdiskcacheandretrievecachesta......
Activating the CLI autocomplete
To activate it, you must run theng completion
command and confirm that you want to enable the autocomplete by typingYes
.
> ng completion? Would you like toenableautocompletion? This willsetup your terminal so pressingTABwhiletyping Angular CLI commands will show possible options and autocomplete arguments.(Enabling autocompletion will modify configuration filesinyour home directory.)> Yes
Finally, just restart your terminal to have autocomplete enabled.
Optional injectors in Embedded Views
Last but not least, we can now pass optional injectors in embedded views. In the past, we had to use other APIs to do that, such as thengComponentOutlet
.
@Directive({selector:'[foo]'})exportclassFooDirectiveimplementsOnInit{constructor(privatevcr:ViewContainerRef,privatetemplateRef:TemplateRef<unknown>){}ngOnInit():void{this.vcr.createEmbeddedView(this.templateRef,{},// context{injector:Injector.create({// pass an injector :)providers:[{provide:'foo',useValue:'bar'}]})});}}
Don't Stop Here
These were the most relevant changes in Angular 14, in my opinion. If you want to see all changes, you can do so by checking out the references in the description.
If you want to dive deeper into the Angular framework, considersubscribing to our newsletter at lucaspaganini.com. It's spam-free. We keep the emails few and valuable.
And if your company is looking for remote web developers, consider contacting my team and me. You can do so at lucaspaganini.com.
As always, references are in the description. Like. Subscribe. Have a great day. And I will see you in the next one.
– Lucas
References
- Angular 14 - Academind on Youtube
- O que há de novo no revolucionário Angular 14 - Andrew Rosário on Medium
- Novidades no Angular v14 - Vida Fullstack
- What is new in Angular 14? - Nevzatopcu on Medium
- Angular v14 is now available! - Angular Blog on Medium
- What’s New in Angular v14 - Netanel Basal
- Unleash the Power of DI Functions in Angular - Netanel Basal
- Getting to know the ENVIRONMENT_INITIALIZER Injection Token in Angular - Netanel Basal
- Typed Reactive Forms in Angular — No Longer a Type Dream - Netanel Basal
- Handling Page Titles in Angular - Netanel Basal
- Angular Standalone Components: Welcome to a World Without NgModule - Netanel Basal
- Pass an Injector to Embedded Views - Netanel Basal
- Setting page title from the route module - Brandon Roberts
- Standalone components with Custom Title Strategy in Angular 14
Top comments(1)

- LocationLos Angeles, CA 90026
- WorkDatabase administrator
- Joined
We can import the required modules in the component itself.prière pour séparer deux personnes en 24h
For further actions, you may consider blocking this person and/orreporting abuse