feat: allow direct scoping of @Injectables to the root injector (#22185)

@Injectable() supports a scope parameter which specifies the target module.
However, it's still difficult to specify that a particular service belongs
in the root injector. A developer attempting to ensure that must either
also provide a module intended for placement in the root injector or target
a module known to already be in the root injector (e.g. BrowserModule).
Both of these strategies are cumbersome and brittle.

Instead, this commit adds a token APP_ROOT_SCOPE which provides a
straightforward way of targeting the root injector directly, without
requiring special knowledge of modules within it.

PR Close #22185
This commit is contained in:
Alex Rickabaugh
2018-02-12 15:23:46 -08:00
committed by Victor Berchet
parent 029dbf0e18
commit 7ac34e42a0
12 changed files with 152 additions and 3 deletions

View File

@ -0,0 +1,43 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {APP_ROOT_SCOPE, Component, Injectable, NgModule, Optional, Self} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {ServerModule} from '@angular/platform-server';
import {RouterModule} from '@angular/router';
import {LazyModuleNgFactory} from './root_lazy.ngfactory';
@Component({
selector: 'root-app',
template: '<router-outlet></router-outlet>',
})
export class AppComponent {
}
export function children(): any {
console.error('children', LazyModuleNgFactory);
return LazyModuleNgFactory;
}
@NgModule({
imports: [
BrowserModule.withServerTransition({appId: 'id-app'}),
ServerModule,
RouterModule.forRoot(
[
{path: '', pathMatch: 'prefix', loadChildren: children},
],
{initialNavigation: 'enabled'}),
],
declarations: [AppComponent],
bootstrap: [AppComponent],
})
export class RootAppModule {
}

View File

@ -0,0 +1,35 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component, NgModule, Optional, Self} from '@angular/core';
import {RouterModule} from '@angular/router';
import {Service} from './root_service';
@Component({
selector: 'lazy-route',
template: '{{service}}:{{serviceInLazyInjector}}',
})
export class RouteComponent {
service: boolean;
serviceInLazyInjector: boolean;
constructor(@Optional() service: Service, @Optional() @Self() lazyService: Service) {
this.service = !!service;
this.serviceInLazyInjector = !!lazyService;
}
}
@NgModule({
declarations: [RouteComponent],
imports: [
RouterModule.forChild([
{path: '', pathMatch: 'prefix', component: RouteComponent},
]),
],
})
export class LazyModule {
}

View File

@ -0,0 +1,15 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {APP_ROOT_SCOPE, Injectable} from '@angular/core';
@Injectable({
scope: APP_ROOT_SCOPE,
})
export class Service {
}