DEV Community

Cover image for Providers and importProvidersFrom() with Standalone Components
Akilah Littlejohn
Akilah Littlejohn

Posted on

Providers and importProvidersFrom() with Standalone Components

In my last article we talked about how to initiate our applications with the bootstrapApplication() function. Today we are going to take a very brief overview of Angular Providers, its configuration, provider scope and how the new Standalone Api handles Angular providers using the importProvidersFrom() inside bootstrapApplication().

What are Angular Providers

In Angular, providers are used to define how a dependency should be instantiated. A provider can be any object or value, but most of the time, it is a class that provides a service or functionality. There are several ways to define providers in Angular, including the providers array in an Angular module, the providers property in a component decorator, or by using the @Injectable decorator to define a service.

Angular Provider Scope

In Angular, the provider scope refers to the scope at which a provider is registered and available for injection. The different levels of scope determines where in the application our providers are available.

Here is an example of how each scope may look like:

Root scope: When a provider is added to the root application Module it is available throughout the entire application.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { UserService } from './user.service';
import { AppComponent } from './app.component';

@NgModule({
  imports: [BrowserModule],
  declarations: [AppComponent],
  providers: [UserService], // Add UserService to providers array

  bootstrap: [AppComponent]
})

export class AppModule { }
Enter fullscreen mode Exit fullscreen mode

Module scope: When a provider is added to a specific module's providers array, it is available to all components and services within "that" module. Our example for the module scope is pretty much the same as the example above for the root scope not including the bootstrap property.

@NgModule({
  declarations: [FeatureComponent],
  imports: [FeatureModule],
  providers: [DataService], // Add DataService to providers array
})
export class MyModule { }
Enter fullscreen mode Exit fullscreen mode

Component scope: When a provider is added to the providers array of a specific component, it is available only to that component and its child components.

@Component({
  selector: 'my-component',
  template: `<h1>Hello, {{username}}!</h1>`,
  providers: [UserService], // Add UserService to providers array
})
export class MyComponent {
  username: string;

  constructor(private userService: UserService) { }

  ngOnInit() {
    this.username = this.userService.getUsername();
  }
}

Enter fullscreen mode Exit fullscreen mode

When a component or service request a dependency, Angular's dependency injection system looks for a provider that can provide that dependency. If a provider is found, Angular creates an instance of the dependency and injects it into the component or service.

@NgModule({
  imports: [BrowserModule],
  declarations: [AppComponent],
  providers: [UserService], // Angular Finds provider.

  bootstrap: [AppComponent]
})

export class AppModule { }

// Any component can now inject the UserService.

import { Component } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-root',
  template: `<h1>Hello, {{username}}!</h1>`
})
export class AppComponent {
  username: string;

  constructor(private userService: UserService) { } // <-- Injects service inside AppComponent's constructor.

  ngOnInit() {
    this.username = this.userService.getUsername();
  }
}
Enter fullscreen mode Exit fullscreen mode

Providing Services with @Injectable()

Providing Services is probably one of the most common use case for providers. The @Injectable decorator is used to decorate a Service Class. The providedIn property located inside the object of @injectable specifies where a Service should be provided. The providedIn property takes a string value that specifies the injector for the service.

Here is an example of providing a Service in the Root Scope with @injectable():

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class MyService {
  constructor() { }

  // ... add methods and properties 
}

Enter fullscreen mode Exit fullscreen mode

In the above code, we first import the Injectable decorator from the @angular/core module. Then, we use the @Injectable decorator to specify that the MyService class should be provided in the root scope. This means that there will be a single instance of the service that is shared across the entire application. Using the @Injectable_** provideIn:’root‘_ should be the preferred for method for making our services available through out the entire application similar to the Root Module. It takes advantage of Angular’s Injection system and is also treeshakable, the metadata tells the compiler which services are actually used in the application and which can be safely removed during the build process.

Provider's in a Standalone RootComponent

In the new bootstrapApplication call, it takes an object as the second argument that has a property named provider, similar to the provider flag in a Component or @NgModule. There, you can provide other Angular modules, such as those from a third-party library, for example, Angular Material or Angular's own libraries like the BrowserAnimationsModule using the new ImportProvidersfrom(). This function cannot be used in a Component or Module only in the bootstrapApplication call. Below is an example of how this property is set to an array that contains providers importing the MatButtonModule which is a module from the Angular Material library providing the necessary providers to the root component.

bootstrapApplication(AppComponent, { 
  providers: [importProvidersFrom(MatButtonModule)]
});
Enter fullscreen mode Exit fullscreen mode

This was definitely a very shallow overview of what providers are and how to use them. I would suggest to learn more by looking at Angular's documentation. My next article covering the new Standalone Api we will learn how to get rid of route modules! If you have any questions or feedback, please don't hesitate to drop them in the comments below or reach me personally. Until next time! Thanks to Sander Elias, for providing helpful insights and being a resource for this article.

Top comments (0)