角度提供者和角度提供者的区别是什么?

以下代码中的 viewProvider 是什么? 它与 viewProvider 有什么不同?

class Greeter {
greet(name:string) {
return 'Hello ' + name + '!';
}
}
@Component({
selector: 'greet',
viewProviders: [
Greeter
],
template: `<needs-greeter></needs-greeter>`
})
class HelloWorld {
}
31195 次浏览

In your example, there is no difference between providers and viewProviders because HelloWorld's template doesn't use <ng-content>. If you were projecting content within <ng-content>...</ng-content>, then Greeter couldn't be injected in the projected content because you're using

viewProviders: [Greeter]

If you wanted Greeter to potentially be injected into the projected content, you'd use

providers: [Greeter]

So viewProviders limits the provider to children other than projected content, while providers allows all children to use the provider. The value is that viewProviders allows you to prevent projected content from messing with your services, which could be especially useful in libraries.

  1. If we want to share one instance of a service across the entirety of our application we configure it in providers on our NgModule.
  2. If we want to have one instance of a service per component, and shared with all the component’s children, we configure it on the providers property on our component decorator. Child is a view children.
  3. If we want to have one instance of a service per component, and shared with only the component’s view children and not the component’s content children, we configure it on the viewProviders property of our component decorator.

share one instance of a service across the entire application -> configure it in providers of root module [AppModule]

share one instance of a service across the entire Module -> configure it in providers of that module

share one instance of a service across the entire Component -> configure it in providers of that Component

share one instance of a service across Component [only ViewChildren not ContentChildren] -> configure it in viewProviders of that Component

It depends on the required scope of service:

  • Module-wide single instance of Service: use providers:[Service] in @NgModule decorator
  • Component-wide single instance of service: use providers:[Service] in @Component decorator. This instance of service will be shared with both ContentChildren & ViewChildren of that component

ContentChildren: Child components which are projected into a component using content-projection i.e. <ng-content></ng-content>

ViewChildren: Child components which are defined inside the component's template and are not projected.

  • Component-wide single instance of service excluding ContentChildren: use viewProviders: [Service] in @Component decorator

A bit off topic, but I want to make a correction to some of the answers, stating that services provided in @NgModule are singletons available to the entire scope of the application. You may run into cases, where that is not true.

Services do not live in modules, they live in injectors. At the very top level Angular has the Null Injector, below that is the Platform Injector and below that, sits the Root Injector. Platform and Root are Module injectors. Weather services, provided in modules, are in the root injector, depends if the modules are eagerly loaded, or not. Services provided in eagerly loaded modules are created in the Root Injector, so in those cases, providing the service in an @NgModule, will make the service a singleton in the root injector. For lazily loaded modules however, angular creates more Module injectors (1 injector for every lazily loaded module), which is below the root injector from docs. In that case providing the service in the @NgModule will not give you a singleton service available to the entire scope of the application, but rather a service, which will be available to the children of the lazily loaded module.

To avoid thinking about this (for angular 6+), if you want a singleton for your entire app, you can tell angular, you want the service in your root injector in the service class itself:

@Injectable({
provideIn: 'root'
})
class MyService...

This will ensure the service is available in angular's root injector