Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: clarify hierarchical injectors #28700

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { browser, element, by } from 'protractor';
import { logging } from 'selenium-webdriver';

describe('Providers and ViewProviders', function () {


beforeEach(() => {
browser.get('');
});

it('shows basic flower emoji', function() {
expect(element.all(by.css('p')).get(0).getText()).toContain('🌺');
});

it('shows whale emoji', function() {
expect(element.all(by.css('p')).get(1).getText()).toContain('🐳');
});

it('shows sunflower from FlowerService', function() {
expect(element.all(by.css('p')).get(8).getText()).toContain('🌻');
});

});

Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// #docregion animal-service
import { Injectable } from '@angular/core';

@Injectable({
providedIn: 'root'
})
export class AnimalService {
emoji = '🐳';
}
// #enddocregion animal-service
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Component } from '@angular/core';
import { FlowerService } from './flower.service';
import { AnimalService } from './animal.service';


@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
// #docregion injection
export class AppComponent {
constructor(public flower: FlowerService) {}
}
// #enddocregion injection
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

<h2>From AppComponent:</h2>
<!-- #docregion binding-flower -->
<p>Emoji from FlowerService: {{flower.emoji}}</p>
<!-- #enddocregion binding-flower -->
<!-- #docregion binding-animal -->
<p>Emoji from AnimalService: {{animal.emoji}}</p>
<!-- #enddocregion binding-animal -->

<hr />

<h2>From ChildComponent:</h2>
<!-- #docregion content-projection -->
<app-child><app-inspector></app-inspector></app-child>
<!-- #enddocregion content-projection -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Component } from '@angular/core';
import { FlowerService } from './flower.service';
import { AnimalService } from './animal.service';


@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
// #docregion inject-animal-service
export class AppComponent {
constructor(public flower: FlowerService, public animal: AnimalService) {}
}
// #enddocregion inject-animal-service
17 changes: 17 additions & 0 deletions aio/content/examples/providers-viewproviders/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { ChildComponent } from './child/child.component';
import { InspectorComponent } from './inspector/inspector.component';

// #docregion appmodule
@NgModule({
imports: [ BrowserModule, FormsModule ],
declarations: [ AppComponent, ChildComponent, InspectorComponent ],
bootstrap: [ AppComponent ],
providers: []
})
export class AppModule { }
// #enddocregion appmodule
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Component, OnInit, Host, SkipSelf, Optional } from '@angular/core';
import { FlowerService } from '../flower.service';

// #docregion flowerservice
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css'],
// use the providers array to provide a service
providers: [{ provide: FlowerService, useValue: { emoji: '🌻' } }]
})

export class ChildComponent {
// inject the service
constructor( public flower: FlowerService) { }
}

// #enddocregion flowerservice

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.container {
border: 1px solid darkblue;
padding: 1rem;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!-- #docplaster -->
<!-- #docregion child-component -->
<!-- #docregion flower-binding -->
<p>Emoji from FlowerService: {{flower.emoji}}</p>
<!-- #enddocregion flower-binding -->
<!-- #docregion animal-binding -->
<p>Emoji from AnimalService: {{animal.emoji}}</p>
<!-- #enddocregion animal-binding -->

<div class="container">
<h3>Content projection</h3>
<!-- #enddocregion child-component -->
<p>The following is coming from content. It doesn't get to see the puppy because the puppy is declared inside the view only.</p>
<!-- #docregion child-component -->
<ng-content></ng-content>
</div>

<h3>Inside the view</h3>
<!-- #enddocregion child-component -->
<p>The following is inside the view so it does see the puppy.</p>
<!-- #docregion child-component -->
<app-inspector></app-inspector>
<!-- #enddocregion child-component -->

Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// #docplaster
import { Component, OnInit, Host, SkipSelf, Optional } from '@angular/core';
import { FlowerService } from '../flower.service';
import { AnimalService } from '../animal.service';

// #docregion provide-animal-service
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css'],
// provide services
providers: [{ provide: FlowerService, useValue: { emoji: '🌻' } }],
viewProviders: [{ provide: AnimalService, useValue: { emoji: '🐶' } }]
})

export class ChildComponent {
// inject service
constructor( public flower: FlowerService, public animal: AnimalService) { }
// #enddocregion provide-animal-service

// viewProviders ensures that only the view gets to see this.
// With the AnimalService in the viewProviders, the
// InspectorComponent doesn't get to see it because the
// inspector is in the content.


// constructor( public flower: FlowerService, @Optional() @Host() public animal: AnimalService) { }

// Comment out the above constructor and alternately
// uncomment the two following constructors to see the
// effects of @Host() and @Host() + @SkipSelf().

// constructor(
// @Host() public animal : AnimalService,
// @Host() @Optional() public flower : FlowerService) { }

// constructor(
// @SkipSelf() @Host() public animal : AnimalService,
// @SkipSelf() @Host() @Optional() public flower : FlowerService) { }

// #docregion provide-animal-service
}
// #enddocregion provide-animal-service

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Injectable } from '@angular/core';

// #docregion flowerservice
@Injectable({
providedIn: 'root'
})
export class FlowerService {
emoji = '🌺';
}
// #enddocregion flowerservice

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<!-- #docregion binding -->
<p>Emoji from FlowerService: {{flower.emoji}}</p>
<p>Emoji from AnimalService: {{animal.emoji}}</p>
<!-- #enddocregion binding -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Component } from '@angular/core';
import { FlowerService } from '../flower.service';
import { AnimalService } from '../animal.service';

@Component({
selector: 'app-inspector',
templateUrl: './inspector.component.html',
styleUrls: ['./inspector.component.css']
})
// #docregion injection
export class InspectorComponent {
constructor(public flower: FlowerService, public animal: AnimalService) { }
}
// #enddocregion injection
14 changes: 14 additions & 0 deletions aio/content/examples/providers-viewproviders/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>providers vs. viewProviders</title>
<base href="/">

<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>
12 changes: 12 additions & 0 deletions aio/content/examples/providers-viewproviders/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.log(err));
10 changes: 10 additions & 0 deletions aio/content/examples/providers-viewproviders/stackblitz.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"description": "Inputs and Outputs",
"files": [
"!**/*.d.ts",
"!**/*.js",
"!**/*.[1,2].*"
],
"file": "src/app/app.component.ts",
"tags": ["Inputs and Outputs"]
}
21 changes: 21 additions & 0 deletions aio/content/examples/resolution-modifiers/e2e/src/app.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { browser, element, by } from 'protractor';

describe('Resolution-modifiers-example', function () {

beforeAll(function () {
browser.get('');
});

it('shows basic flower emoji', function() {
expect(element.all(by.css('p')).get(0).getText()).toContain('🌸');
});

it('shows basic leaf emoji', function() {
expect(element.all(by.css('p')).get(1).getText()).toContain('🌿');
});

it('shows yellow flower in host child', function() {
expect(element.all(by.css('p')).get(9).getText()).toContain('🌼');
});

});
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<h1>DI resolution modifiers</h1>

<p>Basic flower service: {{flower.emoji}}</p>
<p>Basic leaf service: {{leaf.emoji}}</p>

<app-optional></app-optional>

<app-self></app-self>

<app-self-no-data></app-self-no-data>

<app-skipself></app-skipself>

<app-host-parent></app-host-parent>
13 changes: 13 additions & 0 deletions aio/content/examples/resolution-modifiers/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Component } from '@angular/core';
import { LeafService } from './leaf.service';
import { FlowerService } from './flower.service';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
constructor(public flower: FlowerService, public leaf: LeafService) {}
}
33 changes: 33 additions & 0 deletions aio/content/examples/resolution-modifiers/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
;
import { OptionalComponent } from './optional/optional.component';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { SelfNoDataComponent } from './self-no-data/self-no-data.component';
import { HostComponent } from './host/host.component';
import { SelfComponent } from './self/self.component';
import { SkipselfComponent } from './skipself/skipself.component';
import { HostParentComponent } from './host-parent/host-parent.component';
import { HostChildComponent } from './host-child/host-child.component';

@NgModule({
imports: [
BrowserModule,
FormsModule
],
declarations: [
AppComponent,
OptionalComponent,
SelfComponent,
SelfNoDataComponent,
HostComponent,
SkipselfComponent,
HostParentComponent,
HostChildComponent
],
bootstrap: [AppComponent],
providers: []
})
export class AppModule { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Injectable } from '@angular/core';

@Injectable({
providedIn: 'root' // provide this service in the root ModuleInjector

})
export class FlowerService {
emoji = '🌸';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.section {
border: 2px solid #369;
padding: 1rem;
margin: 1rem 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="section">
<h2>Child of @Host() Component</h2>
<p>Flower emoji: {{flower.emoji}}</p>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Component } from '@angular/core';
import { FlowerService } from '../flower.service';

@Component({
selector: 'app-host-child',
templateUrl: './host-child.component.html',
styleUrls: ['./host-child.component.css']
})
export class HostChildComponent {
constructor(public flower: FlowerService) { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.section {
border: 2px solid #369;
padding: 1rem;
margin: 1rem 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="section">
<h2>Parent of @Host() Component</h2>
<p>Flower emoji: {{flower.emoji}}</p>
<app-host></app-host>
</div>