What is new in Angular 14?
Honestly, they haven’t brought a lot of features into a single major version for a while, so the community seems to be thrilled and looking forward to it.
In this article, we’ll see the features of Angular 14. Here are the features that I am going to talk about.
It’s crystal clear that the community is getting bored with NgModules even if there are few people in love with them. Since Angular 14, we will be able to develop an application without any modules even and even AppModule.
Let’s create a new Angular 14 app and see how standalone components work.
To create that, run the following command;
The next step is converting AppComponent into a standalone one, so when your application is created, update the main.ts as below;
Then delete the app.module.ts 🚀
Then quickly update app.component.ts and mark it as standalone
Now we need to import Angular Router and define the routes. That was already done in app.module.ts but we just deleted that.
Since Angular 14, we can import providers in bootstrapApplication() method.
As you can understand from its naming, importProvidersFrom() function extracting providers from NgModules and moduleWithProviders.
Lastly, to make router-outlet directive work, we should import RouterModule in our AppComponent, so we should update it as following;
Now, our application should be working fine with an empty route config. Before deeply diving into route config, let’s create another standalone TitleComponent and use it.
To create a new standalone component, we can use a built-in Angular schematic;
When you run the command, you will discover that it didn’t change anywhere else. It just created html/<style>/ts/spec.ts files. Welcome to the world without NgModules. 🚀
Then, we can proceed with title.component.html.
And TitleComponent is ready to use!
Finally, we can start using it by updating AppComponent
We must import all of the modules and dependent components/pipes/directives into the standalone component, so let’s import TitleComponent!
Yay! Everything is working fine! Congrats, you have created standalone components, and you know how it works!
Before moving to the Router configuration, let’s create three new standalone components named HomeComponent, AboutComponent and ContactUsComponent.
Now we are ready to dive into the Router configuration deeply. We left that as an empty array before, so we should fill that.
We will configure 3 different paths on our root level router configuration.
Let’s go step by step and update the configuration accordingly.
Since it’s an eagerly loaded path, there are no changes. We can just configure that as we used to.
Instead of using loadChildren, we are going to use loadComponent property to lazy load standalone component.
As you can see, we directly referred ContactUsComponent instead of a module.
We will use loadChildren property. Since there are sub-routes on about path we will import the sub-routes instead of AboutComponent.
To sum up, we have not defined any NgModule even though we have 3 routes. That is how standalone components work.
Angular 14 will be a game changer for dependency injection. The great news is that we will be able to use the inject() in components, directives, and pipes, and thus we can create reusable functions which use dependency injection.
Let’s see what we were doing before Angular 14 to create a new subscription that needs to be destroyed.
Thanks to the inject(), we can get rid of the ngOnDestroy lifecycle and destroy the subscriptions by creating a new Rxjs operator. See the example below.
We created a reusable Rxjs operator named takeUntilDestroy$ and automatically destroyed our subscription by using that.
Unfortunately, we have a limitation while using inject() function.
The inject function has to be called in injection context
That means that if we move the takeUntilDestroy Rxjs operator to the ngOnInit lifecycle, it will not work. It must be registered during construction, so it will not be allowed to inject something depending on the component’s input parameters.
We were using @Directive() decorator to take advantage of dependency injection in abstract classes. As you may know, an abstract class with the decorator can make an injection. However, if we need to have some additional injections, we must type constructor() and pass required injections by super() call.
Thanks to the inject() we can get rid of it. Let’s see what we were doing before Angular 14 and what we can do with it.
Let’s use inject() ;
I guess most of the Angular developers implemented their own fancy page title handling functionality. We were using router events, and once the navigation was completed, we read route data and set it as the title.
Finally, Angular Team has published a built-in and great solution for that. We will have a title attribute on the route config, and once the router hits the route, it will automatically update the title. Additionally, we can use a resolver to grab data to generate the title,
Last but not least about the feature, we have a new InjectionToken named TitleStrategy that allows us to manipulate the title. For example, we can prefix the company name to the route title.
We already know that we can get rid of all NgModules thanks to the standalone components, but what about the providers? How will we provide something?
Angular 14 allows us to add providers into the router config. It’s pretty easy, and they will be provided once a user hits the route.
As you can see on the code, we have provided 2 different values for about and home paths so that HomeComponent will print foo and AboutComponent will print bar.
Sometimes, we may need to call a method on a service when a lazy module instance is created or the application is bootstrapped. We used to use dependency injection in a module to create an instance of a service.
Imagine that you have a ActivityLoggerService which logs router events, so the solution before v14 is creating a module below and calling the listen() method of the service in the constructor().
Thanks to the environment initializer, we don’t need to use the tricky way to call listen(). Here you can see the same implementation with the environment initializer feature.
If we need to call that when a user hits a lazy loaded route, we can simply provide it as a route provider.
Eventually, Reactive Forms will be type-safe with Angular v14. As you already know, it has no type-safe implementation, so we were dealing with the typo issues in our reactive forms. Let’s move to the details by an example.
Imagine that you have the following reactive form on your Angular 13 project.
When you run ng update command to migrate your application to Angular 14, your form will be changed as the following.
The schematic replaced FormBuilder with UntypedFormBuilder, so we can understand that our FormGroup is still not type-safe. Let’s convert it into a type-safe by creating an interface and marking the website optional.
We marked the form control named website as optional, so it’s allowed to be removed. On the other hand, we cannot remove the control that is not optional.
One of the fancy features of Angular 14 is that we are allowed to create a new injector and pass it to the embedded view, so we will be able to bring new providers into a new injector.
Angular CLI will provide real-time type ahead auto-completion. You can just type ng and press TAB. It will show all possible commands with descriptions. Enter to choose one.
It looks like Angular v14 contains a lot of useful updates. Since it is still not released, the features may be changed. I will keep the article up-to-date until the official release.
See you in another article!