diff --git a/aio/content/examples/dependency-injection/e2e/app.e2e-spec.ts b/aio/content/examples/dependency-injection/e2e/app.e2e-spec.ts index b61acf3a1e..472f1411fd 100644 --- a/aio/content/examples/dependency-injection/e2e/app.e2e-spec.ts +++ b/aio/content/examples/dependency-injection/e2e/app.e2e-spec.ts @@ -178,6 +178,11 @@ describe('Dependency Injection Tests', function () { expect(heroes.count()).toBeGreaterThan(0); }); + it('authorized user should have multiple authorized heroes with tree-shakeable HeroesService', function () { + let heroes = element.all(by.css('#tspAuthorized app-hero-list div')); + expect(heroes.count()).toBeGreaterThan(0); + }); + it('authorized user should have secret heroes', function () { let heroes = element.all(by.css('#authorized app-hero-list div')); expect(heroes.count()).toBeGreaterThan(0); diff --git a/aio/content/examples/dependency-injection/src/app/app.component.ts b/aio/content/examples/dependency-injection/src/app/app.component.ts index f9b4dc9842..b69856fa0a 100644 --- a/aio/content/examples/dependency-injection/src/app/app.component.ts +++ b/aio/content/examples/dependency-injection/src/app/app.component.ts @@ -21,6 +21,7 @@ import { UserService } from './user.service';

+ ` }) diff --git a/aio/content/examples/dependency-injection/src/app/app.module.ts b/aio/content/examples/dependency-injection/src/app/app.module.ts index 0b5f81b9fe..85becdb3b9 100644 --- a/aio/content/examples/dependency-injection/src/app/app.module.ts +++ b/aio/content/examples/dependency-injection/src/app/app.module.ts @@ -6,6 +6,7 @@ import { APP_CONFIG, HERO_DI_CONFIG } from './app.config'; import { AppComponent } from './app.component'; import { CarComponent } from './car/car.component'; import { HeroesComponent } from './heroes/heroes.component'; +import { HeroesTspComponent } from './heroes/heroes-tsp.component'; import { HeroListComponent } from './heroes/hero-list.component'; import { InjectorComponent } from './injector.component'; import { Logger } from './logger.service'; @@ -25,6 +26,7 @@ import { ProvidersModule } from './providers.module'; CarComponent, HeroesComponent, // #enddocregion ngmodule + HeroesTspComponent, HeroListComponent, InjectorComponent, TestComponent diff --git a/aio/content/examples/dependency-injection/src/app/heroes/hero.module.ts b/aio/content/examples/dependency-injection/src/app/heroes/hero.module.ts new file mode 100644 index 0000000000..7f422d5d79 --- /dev/null +++ b/aio/content/examples/dependency-injection/src/app/heroes/hero.module.ts @@ -0,0 +1,6 @@ +// #docregion +import { NgModule } from '@angular/core'; + +@NgModule({}) +export class HeroModule { +} diff --git a/aio/content/examples/dependency-injection/src/app/heroes/hero.service.0.ts b/aio/content/examples/dependency-injection/src/app/heroes/hero.service.0.ts index d496f9608c..c8136b7db5 100644 --- a/aio/content/examples/dependency-injection/src/app/heroes/hero.service.0.ts +++ b/aio/content/examples/dependency-injection/src/app/heroes/hero.service.0.ts @@ -1,6 +1,8 @@ import { Injectable } from '@angular/core'; -@Injectable() +@Injectable({ + providedIn: 'root', +}) export class HeroService { constructor() { } } diff --git a/aio/content/examples/dependency-injection/src/app/heroes/hero.service.1.ts b/aio/content/examples/dependency-injection/src/app/heroes/hero.service.1.ts index 75b12d7c44..908d75ee65 100644 --- a/aio/content/examples/dependency-injection/src/app/heroes/hero.service.1.ts +++ b/aio/content/examples/dependency-injection/src/app/heroes/hero.service.1.ts @@ -2,7 +2,9 @@ import { Injectable } from '@angular/core'; import { HEROES } from './mock-heroes'; -@Injectable() +@Injectable({ + providedIn: 'root', +}) export class HeroService { getHeroes() { return HEROES; } } diff --git a/aio/content/examples/dependency-injection/src/app/heroes/hero.service.2.ts b/aio/content/examples/dependency-injection/src/app/heroes/hero.service.2.ts index 0069b598db..a4c1adcd1b 100644 --- a/aio/content/examples/dependency-injection/src/app/heroes/hero.service.2.ts +++ b/aio/content/examples/dependency-injection/src/app/heroes/hero.service.2.ts @@ -3,7 +3,9 @@ import { Injectable } from '@angular/core'; import { HEROES } from './mock-heroes'; import { Logger } from '../logger.service'; -@Injectable() +@Injectable({ + providedIn: 'root', +}) export class HeroService { // #docregion ctor diff --git a/aio/content/examples/dependency-injection/src/app/heroes/hero.service.3.ts b/aio/content/examples/dependency-injection/src/app/heroes/hero.service.3.ts new file mode 100644 index 0000000000..2d43704de0 --- /dev/null +++ b/aio/content/examples/dependency-injection/src/app/heroes/hero.service.3.ts @@ -0,0 +1,13 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { HEROES } from './mock-heroes'; + +@Injectable({ + // we declare that this service should be created + // by the root application injector. + + providedIn: 'root', +}) +export class HeroService { + getHeroes() { return HEROES; } +} diff --git a/aio/content/examples/dependency-injection/src/app/heroes/hero.service.4.ts b/aio/content/examples/dependency-injection/src/app/heroes/hero.service.4.ts new file mode 100644 index 0000000000..0b77c78545 --- /dev/null +++ b/aio/content/examples/dependency-injection/src/app/heroes/hero.service.4.ts @@ -0,0 +1,14 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { HeroModule } from './hero.module'; +import { HEROES } from './mock-heroes'; + +@Injectable({ + // we declare that this service should be created + // by any injector that includes HeroModule. + + providedIn: HeroModule, +}) +export class HeroService { + getHeroes() { return HEROES; } +} diff --git a/aio/content/examples/dependency-injection/src/app/heroes/hero.service.ts b/aio/content/examples/dependency-injection/src/app/heroes/hero.service.ts index 02c8e4a85c..6c6fc27037 100644 --- a/aio/content/examples/dependency-injection/src/app/heroes/hero.service.ts +++ b/aio/content/examples/dependency-injection/src/app/heroes/hero.service.ts @@ -2,8 +2,14 @@ import { Injectable } from '@angular/core'; import { HEROES } from './mock-heroes'; import { Logger } from '../logger.service'; +import { UserService } from '../user.service'; -@Injectable() +@Injectable({ + providedIn: 'root', + useFactory: (logger: Logger, userService: UserService) => + new HeroService(logger, userService.user.isAuthorized), + deps: [Logger, UserService], +}) export class HeroService { // #docregion internals constructor( diff --git a/aio/content/examples/dependency-injection/src/app/heroes/heroes-tsp.component.ts b/aio/content/examples/dependency-injection/src/app/heroes/heroes-tsp.component.ts new file mode 100644 index 0000000000..4d6c01b231 --- /dev/null +++ b/aio/content/examples/dependency-injection/src/app/heroes/heroes-tsp.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; + +/** + * A version of `HeroesComponent` that does not provide the `HeroService` (and thus relies on its + * `Injectable`-declared provider) in order to function. + * + * TSP stands for Tree-Shakeable Provider. + */ +@Component({ + selector: 'app-heroes-tsp', + template: ` +

Heroes

+ + ` +}) +export class HeroesTspComponent { } diff --git a/aio/content/examples/dependency-injection/src/app/tree-shaking/app.module.ts b/aio/content/examples/dependency-injection/src/app/tree-shaking/app.module.ts new file mode 100644 index 0000000000..31d79ffc23 --- /dev/null +++ b/aio/content/examples/dependency-injection/src/app/tree-shaking/app.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; +import { ServiceModule } from './service-and-module'; + +// #docregion +@NgModule({ + imports: [ + BrowserModule, + RouterModule.forRoot([]), + ServiceModule, + ], +}) +export class AppModule { +} diff --git a/aio/content/examples/dependency-injection/src/app/tree-shaking/service-and-module.ts b/aio/content/examples/dependency-injection/src/app/tree-shaking/service-and-module.ts new file mode 100644 index 0000000000..11100e3ffe --- /dev/null +++ b/aio/content/examples/dependency-injection/src/app/tree-shaking/service-and-module.ts @@ -0,0 +1,14 @@ +// #docregion +import { Injectable, NgModule } from '@angular/core'; + +@Injectable() +export class Service { + doSomething(): void { + } +} + +@NgModule({ + providers: [Service], +}) +export class ServiceModule { +} diff --git a/aio/content/examples/dependency-injection/src/app/tree-shaking/service.0.ts b/aio/content/examples/dependency-injection/src/app/tree-shaking/service.0.ts new file mode 100644 index 0000000000..50607d7375 --- /dev/null +++ b/aio/content/examples/dependency-injection/src/app/tree-shaking/service.0.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@angular/core'; + +// #docregion +@Injectable({ + providedIn: 'root', + useFactory: () => new Service('dependency'), +}) +export class Service { + constructor(private dep: string) { + } +} diff --git a/aio/content/examples/dependency-injection/src/app/tree-shaking/service.ts b/aio/content/examples/dependency-injection/src/app/tree-shaking/service.ts new file mode 100644 index 0000000000..2013120432 --- /dev/null +++ b/aio/content/examples/dependency-injection/src/app/tree-shaking/service.ts @@ -0,0 +1,8 @@ +import { Injectable } from '@angular/core'; + +// #docregion +@Injectable({ + providedIn: 'root', +}) +export class Service { +} diff --git a/aio/content/examples/dependency-injection/stackblitz.json b/aio/content/examples/dependency-injection/stackblitz.json index d487673f5e..131d2a671c 100644 --- a/aio/content/examples/dependency-injection/stackblitz.json +++ b/aio/content/examples/dependency-injection/stackblitz.json @@ -3,7 +3,7 @@ "files":[ "!**/*.d.ts", "!**/*.js", - "!**/*.[0,1,2].*", + "!**/*.[0,1,2,3,4].*", "!**/dummy.module.ts" ], "tags": ["dependency", "di"] diff --git a/aio/content/examples/providers/src/app/app.module.ts b/aio/content/examples/providers/src/app/app.module.ts index 9ec63c01cd..7152c203c8 100644 --- a/aio/content/examples/providers/src/app/app.module.ts +++ b/aio/content/examples/providers/src/app/app.module.ts @@ -6,7 +6,6 @@ import { UserService } from './user.service'; @NgModule({ imports: [ BrowserModule ], - providers: [ UserService ], declarations: [ AppComponent ], bootstrap: [ AppComponent ] }) diff --git a/aio/content/examples/providers/src/app/user.module.ts b/aio/content/examples/providers/src/app/user.module.ts new file mode 100644 index 0000000000..0b3b67514b --- /dev/null +++ b/aio/content/examples/providers/src/app/user.module.ts @@ -0,0 +1,9 @@ +import { NgModule } from '@angular/core'; + +import { UserService } from './user.service'; + +@NgModule({ + providers: [UserService], +}) +export class UserModule { +} diff --git a/aio/content/examples/providers/src/app/user.service.0.ts b/aio/content/examples/providers/src/app/user.service.0.ts new file mode 100644 index 0000000000..8988a99309 --- /dev/null +++ b/aio/content/examples/providers/src/app/user.service.0.ts @@ -0,0 +1,7 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root', +}) +export class UserService { +} diff --git a/aio/content/examples/providers/src/app/user.service.1.ts b/aio/content/examples/providers/src/app/user.service.1.ts new file mode 100644 index 0000000000..64ee94b72d --- /dev/null +++ b/aio/content/examples/providers/src/app/user.service.1.ts @@ -0,0 +1,8 @@ +import { Injectable } from '@angular/core'; +import { UserModule } from './user.module'; + +@Injectable({ + providedIn: UserModule, +}) +export class UserService { +} diff --git a/aio/content/examples/providers/src/app/user.service.spec.ts b/aio/content/examples/providers/src/app/user.service.spec.ts index 02fbc8d952..dcf5565717 100644 --- a/aio/content/examples/providers/src/app/user.service.spec.ts +++ b/aio/content/examples/providers/src/app/user.service.spec.ts @@ -3,9 +3,7 @@ import { UserService } from './user.service'; describe('UserService', () => { beforeEach(() => { - TestBed.configureTestingModule({ - providers: [UserService] - }); + TestBed.configureTestingModule({}); }); it('should ...', inject([UserService], (service: UserService) => { diff --git a/aio/content/examples/providers/src/app/user.service.ts b/aio/content/examples/providers/src/app/user.service.ts index 2cb7a87759..096d1c8fb1 100644 --- a/aio/content/examples/providers/src/app/user.service.ts +++ b/aio/content/examples/providers/src/app/user.service.ts @@ -5,7 +5,9 @@ export class User { name: string; } -@Injectable() +@Injectable({ + providedIn: 'root', +}) export class UserService { constructor() { } diff --git a/aio/content/examples/providers/stackblitz.json b/aio/content/examples/providers/stackblitz.json index 68593b9051..9f21337a05 100644 --- a/aio/content/examples/providers/stackblitz.json +++ b/aio/content/examples/providers/stackblitz.json @@ -3,7 +3,7 @@ "files": [ "!**/*.d.ts", "!**/*.js", - "!**/*.[1,2].*" + "!**/*.[0,1,2].*" ], "file": "src/app/app.component.ts", "tags": ["providers"] diff --git a/aio/content/examples/styleguide/src/07-03/app/app.component.ts b/aio/content/examples/styleguide/src/07-03/app/app.component.ts index f4d25e1ab6..224ab34619 100644 --- a/aio/content/examples/styleguide/src/07-03/app/app.component.ts +++ b/aio/content/examples/styleguide/src/07-03/app/app.component.ts @@ -8,6 +8,5 @@ import { HeroService } from './heroes'; template: ` `, - providers: [HeroService] }) export class AppComponent {} diff --git a/aio/content/examples/styleguide/src/07-03/app/heroes/shared/hero.service.ts b/aio/content/examples/styleguide/src/07-03/app/heroes/shared/hero.service.ts index 4e2f993250..d3d8857caa 100644 --- a/aio/content/examples/styleguide/src/07-03/app/heroes/shared/hero.service.ts +++ b/aio/content/examples/styleguide/src/07-03/app/heroes/shared/hero.service.ts @@ -5,7 +5,9 @@ import { Observable, of } from 'rxjs'; import { Hero } from './hero.model'; -@Injectable() +@Injectable({ + providedIn: 'root', +}) export class HeroService { getHeroes() { let heroes: Hero[] = [];