Angular Standalone Components - No Ngmodules Anymore
In this video you will learn how to create and use standalone components inside Angular.
Starting from Angular 15 we have such thing which is called standalone components.
Which essentially means that we should not create a module every single time when we need to create a component. Actually we simply move all properties and configuration from module to component.
This is why in this post I want to refactor Angular project to the usage of standalone components.
npx -p @angular/cli@15 ng g c foo --standalone
Here we used @angular/cli@15
to execute commands with Angular 15 version. What we used is ng g c foo
which means generate component with name foo
. The attribute standalone
means that module won't be created but just a standalone component.
As you can see module won't created by just a component. Now let's check how it looks like.
@Component({
selector: 'app-foo',
standalone: true,
imports: [CommonModule],
templateUrl: './foo.component.html',
styleUrls: ['./foo.component.css'],
})
export class FooComponent {}
First of all we can see here a standalone
property which shows that this is a standalone component. Secondly we see here imports
property which previously was in module. Now it is moved to component and we can use it in exactly the same way.
Now let's try to generate one more component and use it inside FooComponent
.
npx -p @angular/cli@15 ng g c bar --standalone
Now let's register BarComponent
inside our FooComponent
like we previously did with modules.
@Component({
selector: 'app-foo',
standalone: true,
imports: [CommonModule, BarComponent],
templateUrl: './foo.component.html',
styleUrls: ['./foo.component.css'],
})
export class FooComponent {}
You can really think about it like a component-module which we inject as a dependency in other component-module.
Now let's render Bar component in the markup.
<p>foo works!</p>
<app-bar></app-bar>
As you can see both components are rendering on the page and we didn't need to create an additional module for them.
Lazy loading
The next question that you for sure have is how we can lazy load our Foo
component? Previously we lazy loaded a module so it is a valid question.
export const routes: Routes = [
{
path: 'foo',
loadComponent: () =>
import('./foo/foo.component').then((m) => m.FooComponent),
},
];
We create a lazy route just like previously but we provided a component inside.
If we jump to /foo
route our component will be successfully rendered.
Standalone app component
Now we have even more interesting stuff. We still have our normal app.component.ts
but we can convert it to standalone just like other components.
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
standalone: true,
imports: [FooComponent],
})
export class AppComponent {
title = 'app';
}
But if we make it standalone and imported FooComponent
inside then we don't need app.module
anymore. Now app.component
is our main and most important point of entrance.
This changes won't work if we just remove app.module
because our main.ts
doesn't know how to start application with app.component
.
import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter } from '@angular/router';
import { routes } from './app/app-routing.module';
import { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent, { providers: [provideRouter(routes)] });
This is how we must update our main.ts
. We use bootstrapApplication
function now and provide AppComponent
inside. Additionally we want to register all routes like we did previously. We do that with provideRouter
but inside we just provide an array of routes and not a RouterModule
.
Working with links
The last thing that I want to show you is how to add Router functionality back to our application. If we open browser now we get an error.
In order to fix that we must inject RouterOutlet
module inside our standalone AppComponent
. Additionally to make router links working we must import RouterLink
.
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
standalone: true,
imports: [FooComponent, RouterOutlet, RouterLink],
})
export class AppComponent {
title = 'app';
}
As you can see now we don't have any errors and our application works as before.
Want to conquer your next JavaScript interview? Download my FREE PDF - Pass Your JS Interview with Confidence and start preparing for success today!
📚 Source code of what we've done