Skip to content

Commit

Permalink
docs: clarify hierarchical injectors
Browse files Browse the repository at this point in the history
  • Loading branch information
kapunahelewong committed Mar 14, 2019
1 parent 2064508 commit 33defe2
Show file tree
Hide file tree
Showing 40 changed files with 611 additions and 160 deletions.
30 changes: 30 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,30 @@
'use strict'; // necessary for es6 output in node

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(8).getText()).toContain('🌼');
});

it('shows tulip in nested host g. grandchild', function() {
expect(element.all(by.css('p')).get(11).getText()).toContain('🌷');
});

it('shows tulip in non-nested host g. grandchild', function() {
expect(element.all(by.css('p')).get(12).getText()).toContain('🌸');
});
});
4 changes: 4 additions & 0 deletions aio/content/examples/resolution-modifiers/example-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"build": "build:cli",
"run": "serve:cli"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<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-skipself></app-skipself>

<app-host-parent></app-host-parent>

<app-host-g-grandchild></app-host-g-grandchild>

14 changes: 14 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,14 @@
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) {}
}
41 changes: 41 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,41 @@
;
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 { FlowerService } from './flower.service';
import { LeafService } from './leaf.service';
import { SelfComponent } from './self/self.component';
import { HostComponent } from './host/host.component';
import { SkipselfComponent } from './skipself/skipself.component';
import { HostParentComponent } from './host-parent/host-parent.component';
import { HostChildComponent } from './host-child/host-child.component';
import { HostGrandchildComponent } from './host-grandchild/host-grandchild.component';
import { HostGGrandchildComponent } from './host-g-grandchild/host-g-grandchild.component';





@NgModule({
imports: [
BrowserModule,
FormsModule
],
declarations: [
AppComponent,
OptionalComponent,
SelfComponent,
HostComponent,
SkipselfComponent,
HostParentComponent,
HostChildComponent,
HostGrandchildComponent,
HostGGrandchildComponent
],
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 = "🌸";
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<div class="section">
<h2>Child of @Host() Component</h2>
<p>Flower emoji: {{flower.emoji}}</p>
<i>(Looks up the tree until it encounters @Host())</i>

<app-host-grandchild></app-host-grandchild>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
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,7 @@
<div class="section">
<h2>Great Grandchild of @Host() Component</h2>
<p>Flower emoji: {{flower.emoji}}</p>
<div>
<ng-content> </ng-content>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Component, OnInit } from '@angular/core';
import { FlowerService } from '../flower.service';


@Component({
selector: 'app-host-g-grandchild',
templateUrl: './host-g-grandchild.component.html',
styleUrls: ['./host-g-grandchild.component.css']
})
export class HostGGrandchildComponent implements OnInit {

constructor(public flower: FlowerService) { }

ngOnInit() {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<div class="section">
<h2>Grandchild of @Host() Component with its own @Host()</h2>
<p>Flower emoji: {{flower.emoji}}</p>
<p><i>(@Host() stops it here)</i></p>
<app-host-g-grandchild></app-host-g-grandchild>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Component, OnInit, Host } from '@angular/core';
import { FlowerService} from '../flower.service';


@Component({
selector: 'app-host-grandchild',
templateUrl: './host-grandchild.component.html',
styleUrls: ['./host-grandchild.component.css'],
providers: [{ provide: FlowerService, useValue: { emoji: '🌷' } }]

})
export class HostGrandchildComponent implements OnInit {

constructor(@Host() public flower: FlowerService) { }

ngOnInit() {
}

}
Empty file.
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>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Component } from '@angular/core';
import { FlowerService } from '../flower.service';


@Component({
selector: 'app-host-parent',
templateUrl: './host-parent.component.html',
styleUrls: ['./host-parent.component.css'],
providers: [{ provide: FlowerService, useValue: { emoji: '🌺' } }]

})
export class HostParentComponent {

constructor(public flower: FlowerService) { }

}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<div class="section">
<h2>@Host() Component</h2>
<p>Flower emoji: {{flower.emoji}}</p>
<p><i>(@Host() stops it here)</i></p>
<app-host-child></app-host-child>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Component, Host } from '@angular/core';
import { FlowerService } from '../flower.service';

// #docregion host-component
@Component({
selector: 'app-host',
templateUrl: './host.component.html',
styleUrls: ['./host.component.css'],
// provide the service
providers: [{ provide: FlowerService, useValue: { emoji: '🌼' } }]
})
export class HostComponent {
// use @Host() in the constructor when injecting the service
constructor(@Host() public flower: FlowerService) { }
}
// #enddocregion host-component

// if you take out @Host() and the providers array, flower will be red hibiscus


11 changes: 11 additions & 0 deletions aio/content/examples/resolution-modifiers/src/app/leaf.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Injectable } from '@angular/core';

@Injectable({
providedIn: 'root'
})
// #docregion leafservice
export class LeafService {
emoji = '🌿';
}
// #enddocregion leafservice

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

@Injectable()
export class OptionalService {
}

// This service isn't provided anywhere.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="section">
<h2>@Optional() Component</h2>
<p>This component still works even though the OptionalService (notice @Optional() in the consturctor isn't provided or configured anywhere. Angular goes through tree and visibilty rules, and if it doesn't find the requested service, returns null.</p>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Component, Optional } from '@angular/core';
import { OptionalService } from '../optional.service';

@Component({
selector: 'app-optional',
templateUrl: './optional.component.html',
styleUrls: ['./optional.component.css']
})

// #docregion optional-component
export class OptionalComponent {
constructor(@Optional() public optional: OptionalService) {}
}
// #enddocregion optional-component

// The OptionalService isn't provided here, in the @Injectable providers array, or in the NgModule. If you remove @Optional() from the constructor, you'll get an error.



Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="section">
<h2>@Self() Component</h2>
<p>Leaf emoji: {{leaf.emoji}}</p>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Component, Self } from '@angular/core';
import { LeafService } from '../leaf.service';

// #docregion self-component
@Component({
selector: 'app-self',
templateUrl: './self.component.html',
styleUrls: ['./self.component.css'],
providers: [{ provide: LeafService, useValue: { emoji: '🌱' } }]
})
export class SelfComponent {

constructor(@Self() public leaf: LeafService) { }
}

// #enddocregion self-component

// If you comment out the providers array,
// the app will break because Angular can only look in the
// ElementInjector for this component as long as you use @Self().
// If you remove @Self(), the leaf emoji value will be 🌿 and the app
// will work. With @Self() in the constructor,
// uncomment the providers array and the app will work again, this time with the value of 🌱for leaf.emoji.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="section">
<h2>@SkipSelf() Component</h2>
<p>Leaf emoji: {{leaf.emoji}}</p>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Component, SkipSelf } from '@angular/core';
import { LeafService } from '../leaf.service';

// #docregion skipself-component
@Component({
selector: 'app-skipself',
templateUrl: './skipself.component.html',
styleUrls: ['./skipself.component.css'],
// Angular would ignore this LeafService instance
providers: [{ provide: LeafService, useValue: { emoji: '🌱' } }]
})
export class SkipselfComponent {
// Use @SkipSelf() in the constructor
constructor(@SkipSelf() public leaf: LeafService) { }
}
// #enddocregion skipself-component

// @SkipSelf(): Specifies that the dependency resolution should start from the parent injector, not here.
14 changes: 14 additions & 0 deletions aio/content/examples/resolution-modifiers/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>NgmodulesExample</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>Loading...</app-root>
</body>
</html>
11 changes: 11 additions & 0 deletions aio/content/examples/resolution-modifiers/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
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);
10 changes: 10 additions & 0 deletions aio/content/examples/resolution-modifiers/stackblitz.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"description": "NgModules",
"files": [
"!**/*.d.ts",
"!**/*.js",
"!**/*.[1,2].*"
],
"file": "src/app/app.component.ts",
"tags": ["NgModules"]
}

0 comments on commit 33defe2

Please sign in to comment.