Angular Standalone Components - No Ngmodules Anymore
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.

Standalone comps

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.

Cli

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>

Foo 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.

Foo bar

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.

Router outlet

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.

And actually if you want to learn Angular with NgRx from empty folder to a fully functional production application make sure to check my Angular and NgRx - Building Real Project From Scratch course.

📚 Source code of what we've done