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:

committed by
Victor Berchet

parent
029dbf0e18
commit
7ac34e42a0
@ -16,6 +16,7 @@ ng_module(
|
||||
"//packages/core",
|
||||
"//packages/platform-browser",
|
||||
"//packages/platform-server",
|
||||
"//packages/router",
|
||||
"@rxjs",
|
||||
],
|
||||
)
|
||||
|
@ -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 {
|
||||
}
|
@ -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 {
|
||||
}
|
@ -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 {
|
||||
}
|
@ -10,6 +10,7 @@ import {enableProdMode} from '@angular/core';
|
||||
import {renderModuleFactory} from '@angular/platform-server';
|
||||
import {BasicAppModuleNgFactory} from 'app_built/src/basic.ngfactory';
|
||||
import {HierarchyAppModuleNgFactory} from 'app_built/src/hierarchy.ngfactory';
|
||||
import {RootAppModuleNgFactory} from 'app_built/src/root.ngfactory';
|
||||
import {SelfAppModuleNgFactory} from 'app_built/src/self.ngfactory';
|
||||
import {TokenAppModuleNgFactory} from 'app_built/src/token.ngfactory';
|
||||
|
||||
@ -55,4 +56,14 @@ describe('ngInjectableDef Bazel Integration', () => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('APP_ROOT_SCOPE works', done => {
|
||||
renderModuleFactory(RootAppModuleNgFactory, {
|
||||
document: '<root-app></root-app>',
|
||||
url: '/',
|
||||
}).then(html => {
|
||||
expect(html).toMatch(/>true:false<\//);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user