Skip to content
This repository was archived by the owner on Dec 4, 2017. It is now read-only.

Commit 73b9602

Browse files
committed
first draft of Dart text
1 parent 27c4077 commit 73b9602

File tree

2 files changed

+110
-33
lines changed

2 files changed

+110
-33
lines changed

public/docs/dart/latest/guide/dependency-injection.jade

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ include ../_util-fns
1313
'dependency-injection/dart/lib/car/car.dart, dependency-injection/dart/lib/car/car_no_di.dart',
1414
'car-ctor, car-ctor',
1515
'lib/car/car.dart (excerpt with DI), lib/car/car.dart (excerpt without DI)')(format=".")
16-
+includeShared('{ts}', 'why-3')
1716
+includeShared('{ts}', 'why-3-1')
1817
+includeShared('{ts}', 'why-3-2')
1918
- var stylePattern = { otl: /(new Car.*$)/gm };
@@ -52,7 +51,13 @@ include ../_util-fns
5251
+includeShared('{ts}', 'di-3')
5352
+makeExample('dependency-injection/dart/lib/heroes/hero_service_1.dart',null, 'lib/heroes/hero_service.dart' )
5453
+includeShared('{ts}', 'di-4')
55-
+includeShared('{ts}', 'di-5')
54+
.l-sub-section
55+
:marked
56+
We aren't even pretending this is a real service.
57+
If we were actually getting data from a remote server, the API would have to be asynchronous,
58+
returning a `Future`.
59+
We'd also have to rewrite the way components consume our service.
60+
This is important in general, but not to our current story.
5661
+includeShared('{ts}', 'di-6')
5762
+includeShared('{ts}', 'di-configure-injector-1')
5863
+makeExample('dependency-injection/dart/web/main.dart', 'bootstrap', 'web/main.dart (excerpt)')(format='.')
@@ -77,13 +82,26 @@ include ../_util-fns
7782

7883
Adding a parameter to the constructor isn't all that's happening here.
7984
+makeExample('dependency-injection/dart/lib/heroes/hero_list_component_2.dart', 'ctor')(format=".")
80-
+includeShared('{ts}', 'di-prepare-for-injection-2')
85+
:marked
86+
The constructor parameter has a type: `HeroService`.
87+
The `HeroListComponent` class is also annotated with `@Component`
88+
(scroll up to confirm that fact).
89+
Also recall that the parent component (`HeroesComponent`)
90+
has `providers` information for `HeroService`.
91+
92+
The constructor parameter type, the `@Component` annotation,
93+
and the parent's `providers` information combine to tell the
94+
Angular injector to inject an instance of
95+
`HeroService` whenever it creates a new `HeroListComponent`.
8196
+includeShared('{ts}', 'di-create-injector-implicitly-1')
8297
+makeExample('dependency-injection/dart/lib/car/car_injector.dart','injector-create-and-call')(format=".")
8398
+includeShared('{ts}', 'di-create-injector-implicitly-2')
8499
+includeShared('{ts}', 'di-singleton-services')
100+
101+
// Skip the testing section, for now.
85102
// +includeShared('{ts}', 'di-testing-component-1')
86103
// +includeShared('{ts}', 'di-testing-component-2')
104+
87105
+includeShared('{ts}', 'di-service-service-1')
88106
+makeTabs(
89107
`dependency-injection/dart/lib/heroes/hero_service_2.dart,
@@ -92,16 +110,19 @@ include ../_util-fns
92110
`lib/heroes/hero_service (v.2),
93111
lib/heroes/hero_service (v.1)`)
94112
+includeShared('{ts}', 'di-service-service-2')
95-
+includeShared('{ts}', 'di-injectable')
113+
+includeShared('{ts}', 'di-injectable-1')
114+
+includeShared('{ts}', 'di-injectable-2')
96115

97116
+includeShared('{ts}', 'logger-service-1')
98117
+makeExample(
99118
'dependency-injection/dart/lib/logger_service.dart',null, 'lib/logger_service')
100-
+includeShared('{ts}', 'logger-service-2')
119+
:marked
120+
We're likely to need the same logger service everywhere in our application,
121+
so we put it in the `lib/` folder, and
122+
we register it in the `providers` array of the metadata for our application root component, `AppComponent`.
101123
+makeExample('dependency-injection/dart/lib/providers_component.dart','providers-logger', 'lib/app_component.dart (excerpt)')
102124
+includeShared('{ts}', 'logger-service-3')
103125
+includeShared('{ts}', 'logger-service-4')
104-
+makeExample('dependency-injection/dart/lib/providers_component.dart','import-optional')(format='.')
105126
+includeShared('{ts}', 'logger-service-5')
106127
+makeExample('dependency-injection/dart/lib/providers_component.dart','provider-10-ctor')(format='.')
107128
+includeShared('{ts}', 'logger-service-6')
@@ -112,14 +133,29 @@ include ../_util-fns
112133
+makeExample('dependency-injection/dart/lib/providers_component.dart','providers-logger')
113134
+includeShared('{ts}', 'providers-2')
114135
+includeShared('{ts}', 'providers-provide-1')
136+
:marked
137+
### The *Provider* class
138+
+includeShared('{ts}', 'providers-provide-1-1')
115139
+makeExample('dependency-injection/dart/lib/providers_component.dart','providers-1')
116140
+includeShared('{ts}', 'providers-provide-2')
117141
+makeExample('dependency-injection/dart/lib/providers_component.dart','providers-2')
118-
+includeShared('{ts}', 'providers-provide-3')
119-
+makeExample('dependency-injection/dart/lib/providers_component.dart','providers-3')
120-
+includeShared('{ts}', 'providers-provide-4')
142+
// Don't discuss provide function.
143+
:marked
144+
We supply two arguments to the `Provider` constructor.
145+
+includeShared('{ts}', 'providers-provide-4-2')
121146
+includeShared('{ts}', 'providers-alternative-1')
122147
+makeExample('dependency-injection/dart/lib/providers_component.dart','providers-4')
148+
.callout.is-helpful
149+
header Dart difference: Constants in metadata
150+
:marked
151+
In Dart, the value of a metadata annotation must be a compile-time constant.
152+
For that reason, you can't call functions to get values
153+
to use within an annotation.
154+
Instead, you use constant literals or constant constructors.
155+
For example, a TypeScript or JavaScript program might use
156+
`provide(Logger, {useClass: BetterLogger})` or, equivalently,
157+
`new Provider(Logger, {useClass: BetterLogger})`.
158+
A Dart annotation would instead use the constant value `const Provider(Logger, useClass: BetterLogger)`.
123159
+includeShared('{ts}', 'providers-alternative-2')
124160
+makeExample('dependency-injection/dart/lib/providers_component.dart','EvenBetterLogger')
125161
+includeShared('{ts}', 'providers-alternative-3')
@@ -129,6 +165,7 @@ include ../_util-fns
129165
+includeShared('{ts}', 'providers-aliased-2')
130166
+makeExample('dependency-injection/dart/lib/providers_component.dart','providers-6b')(format=".")
131167
+includeShared('{ts}', 'providers-value-1')
168+
p <b>[PENDING: fix this code? When would you really use a value? maybe if it's initialized from a string?]</b>
132169
+makeExample('dependency-injection/dart/lib/providers_component.dart','silent-logger')(format=".")
133170
+includeShared('{ts}', 'providers-value-2')
134171
+makeExample('dependency-injection/dart/lib/providers_component.dart','providers-7')(format=".")
@@ -151,20 +188,35 @@ include ../_util-fns
151188
+includeShared('{ts}', 'tokens-1')
152189
+makeExample('dependency-injection/dart/lib/injector_component.dart','get-hero-service')(format='.')
153190
+includeShared('{ts}', 'tokens-2')
191+
p <b>[PENDING: How about a better name than ProviderComponent8?]</b>
154192
+makeExample('dependency-injection/dart/lib/providers_component.dart','provider-8-ctor')(format=".")
155193
+includeShared('{ts}', 'tokens-3')
156194
+includeShared('{ts}', 'tokens-non-class-deps-1')
195+
p <b>[PENDING: What's the Dart equivalent of "object hash"? How can we shorten/improve this code?]</b>
157196
+makeExample('dependency-injection/dart/lib/app_config.dart','config','lib/app_config.dart (excerpt)')(format='.')
158197
+includeShared('{ts}', 'tokens-non-class-deps-2')
198+
p <b>[PENDING: That's not right. That text is from the TypeScript version. How should the Dart code/text be different?]</b>
199+
p <b>[PENDING: TypeScript has a whole section here on "Interfaces aren't valid tokens". But they are in Dart!]</b>
200+
.callout.is-helpful
201+
header Dart difference: Interfaces are valid tokens
202+
:marked
203+
In TypeScript, interfaces don't work as provider tokens.
204+
Work arounds include using string tokens or `OpaqueToken` objects
205+
as the first argument to the `Provider` constructor or `provide` function.
206+
Dart doesn't have this problem.
207+
Go ahead and use an interface name
208+
(usually, that's the name of an abstract class)
209+
as the first argument.
159210
+includeShared('{ts}', 'tokens-string-1')
211+
p <b>[PENDING: Where did CONFIG_HASH come from? (lib/app_config.dart) Why does the code use that instead of CONFIG? (only matters if we keep the code, I suppose)]</b>
160212
+makeExample('dependency-injection/dart/lib/providers_component.dart','providers-9a')(format=".")
161213
+includeShared('{ts}', 'tokens-string-2')
214+
p <b>[PENDING: I don't like showing ProviderComponent9a. Also... can we make this code easier to read?]</b>
162215
+makeExample('dependency-injection/dart/lib/providers_component.dart','provider-9a-ctor')(format=".")
163216
+includeShared('{ts}', 'tokens-opaque-1')
164217
+makeExample('dependency-injection/dart/lib/app_config.dart','token')(format='.')
165218
+includeShared('{ts}', 'tokens-opaque-2')
166219
+makeExample('dependency-injection/dart/lib/providers_component.dart','providers-9b')(format=".")
167-
+makeExample('dependency-injection/dart/lib/providers_component.dart','provider-9b-ctor')(format=".")
168220
+includeShared('{ts}', 'tokens-opaque-3')
169221
+makeExample('dependency-injection/dart/lib/app_component.dart','providers', 'lib/app_component.dart (providers)')(format=".")
170222
+makeExample('dependency-injection/dart/lib/app_component.dart','ctor', 'lib/app_component.dart (constructor)')(format=".")

public/docs/ts/latest/guide/dependency-injection.jade

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,16 @@ include ../_util-fns
7373
'dependency-injection/ts/app/car/car.ts, dependency-injection/ts/app/car/car-no-di.ts',
7474
'car-ctor, car-ctor',
7575
'app/car/car.ts (excerpt with DI), app/car/car.ts (excerpt without DI)')(format=".")
76-
// #docregion why-3
76+
// #docregion why-3-1
7777
:marked
7878
See what happened? We moved the definition of the dependencies to the constructor.
7979
Our `Car` class no longer creates an engine or tires.
8080
It just consumes them.
81-
// #enddocregion why-3
82-
// #docregion why-3-1
81+
// #enddocregion why-3-1
82+
// TypeScript only
8383
.l-sub-section
8484
:marked
8585
We also leverage TypeScript's constructor syntax for declaring parameters and properties simultaneously.
86-
// #enddocregion why-3-1
8786
// #docregion why-3-2
8887
:marked
8988
Now we create a car by passing the engine and tires to the constructor.
@@ -315,7 +314,7 @@ include ../_util-fns
315314

316315
+makeExample('dependency-injection/ts/app/heroes/hero-list.component.2.ts', 'ctor')(format=".")
317316

318-
// #docregion di-prepare-for-injection-2
317+
// TypeScript only
319318
:marked
320319
We're writing in TypeScript and have followed the parameter name with a type annotation, `:HeroService`.
321320
The class is also decorated with the `@Component` decorator (scroll up to confirm that fact).
@@ -326,7 +325,6 @@ include ../_util-fns
326325

327326
That's how the Angular injector knows to inject an instance of the `HeroService` when it
328327
creates a new `HeroListComponent`.
329-
// #enddocregion di-prepare-for-injection-2
330328
// #docregion di-create-injector-implicitly-1
331329
:marked
332330
<a id="di-metadata"></a>
@@ -395,39 +393,49 @@ include ../_util-fns
395393
The constructor now asks for an injected instance of a `Logger` and stores it in a private property called `_logger`.
396394
We call that property within our `getHeroes` method when anyone asks for heroes.
397395
// #enddocregion di-service-service-2
398-
// #docregion di-injectable
396+
// #docregion di-injectable-1
397+
- var lang = current.path[1]
398+
- var decoration = lang == 'dart' ? 'annotation' : 'decoration'
399399
:marked
400400
<a id="injectable"></a>
401401
### Why @Injectable?
402-
Notice the `@Injectable()` decoration above the service class.
402+
Notice the `@Injectable()` #{decoration} above the service class.
403403
We haven't seen `@Injectable()` before.
404404
As it happens, we could have added it to our first version of `HeroService`.
405405
We didn't bother because we didn't need it then.
406406

407407
We need it now... now that our service has an injected dependency.
408408
We need it because Angular requires constructor parameter metadata in order to inject a `Logger`.
409+
// #enddocregion di-injectable-1
410+
// TypeScript only?
411+
:marked
409412
As [we mentioned earlier](#di-metadata), **TypeScript only generates metadata for classes that have a decorator.**
410413

414+
// #docregion di-injectable-2
415+
- var lang = current.path[1]
416+
- var a_decorator = lang == 'dart' ? 'an annotation' : 'a decorator'
417+
- var decorated = lang == 'dart' ? 'annotated' : 'decorated'
418+
- var any_decorator = lang == 'dart' ? '' : 'TypeScript generates metadata for any class with a decorator, and any decorator will do.'
411419
.callout.is-helpful
412420
header Always add @Injectable()
413421
:marked
414422
We recommend adding `@Injectable()` to every service class, even those that don't have dependencies
415423
and, therefore, do not technically require it. Here's why:
416424
ul(style="font-size:inherit")
417425
li <b>Future proofing:</b> No need to remember <code>@Injectable</code> when we add a dependency later.
418-
li <b>Consistency:</b> All services follow the same rules, and we don't have to wonder why a decorator is missing.
426+
li <b>Consistency:</b> All services follow the same rules, and we don't have to wonder why #{a_decorator} is missing.
419427
.l-sub-section
420428
:marked
421429
The `HeroesComponent` has an injected dependency too. Why don't we add `@Injectable()` to the `HeroesComponent`?
422430

423-
We *can* add it if we really want to. It isn't necessary because the `HeroesComponent` is already decorated with `@Component`.
424-
TypeScript generates metadata for *any* class with a decorator, and *any* decorator will do.
431+
We *can* add it if we really want to. It isn't necessary because
432+
the `HeroesComponent` is already #{decorated} with `@Component`. #{any_decorator}
425433

426434
.alert.is-critical
427435
:marked
428-
**Always include the parentheses!** Always call `@Injectable()`.
436+
**Always include the parentheses!** Always use `@Injectable()`.
429437
Our application will fail mysteriously if we forget the parentheses.
430-
// #enddocregion di-injectable
438+
// #enddocregion di-injectable-2
431439
// #docregion logger-service-1
432440
.l-main-section
433441
:marked
@@ -440,12 +448,12 @@ include ../_util-fns
440448
// #enddocregion logger-service-1
441449
+makeExample(
442450
'dependency-injection/ts/app/logger.service.ts',null, 'app/logger.service')
443-
// #docregion logger-service-2
451+
452+
// Copied into Dart, due to different directory structure
444453
:marked
445454
We're likely to need the same logger service everywhere in our application,
446455
so we put it at the root level of the application in the `app/` folder, and
447456
we register it in the `providers` array of the metadata for our application root component, `AppComponent`.
448-
// #enddocregion logger-service-2
449457
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-logger', 'app/app.component.ts (excerpt)')
450458
// #docregion logger-service-3
451459
:marked
@@ -468,13 +476,19 @@ code-example(format, language="html").
468476

469477
Our `HeroService` currently requires a `Logger`. What if we could get by without a logger?
470478
We'd use it if we had it, ignore it if we didn't. We can do that.
479+
// #enddocregion logger-service-4
471480
481+
// TypeScript only?
482+
:marked
472483
First import the `@Optional()` decorator.
473-
// #enddocregion logger-service-4
474484
+makeExample('dependency-injection/ts/app/providers.component.ts','import-optional')(format='.')
485+
475486
// #docregion logger-service-5
487+
- var lang = current.path[1]
488+
- var rewrite = lang == 'dart' ? 'Just rewrite' : 'Then rewrite'
489+
- var decorator = lang == 'dart' ? 'annotation' : 'decorator'
476490
:marked
477-
Then rewrite the constructor with `@Optional()` decorator preceding the private `_logger` parameter.
491+
#{rewrite} the constructor with the `@Optional()` #{decorator} preceding the private `_logger` parameter.
478492
That tells the injector that `_logger` is optional.
479493
// #enddocregion logger-service-5
480494
+makeExample('dependency-injection/ts/app/providers.component.ts','provider-10-ctor')(format='.')
@@ -532,10 +546,15 @@ code-example(format, language="html").
532546
// #docregion providers-provide-1
533547
:marked
534548
<a id="provide"></a>
535-
### The *provide* function
549+
// #enddocregion providers-provide-1
536550
551+
// Don't mention provide function in Dart
552+
:marked
553+
### The *Provider* class and *provide* function
554+
// #docregion providers-provide-1-1
555+
:marked
537556
We wrote the `providers` array like this:
538-
// #enddocregion providers-provide-1
557+
// #enddocregion providers-provide-1-1
539558
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-1')
540559
// #docregion providers-provide-2
541560
:marked
@@ -544,22 +563,26 @@ code-example(format, language="html").
544563
// #enddocregion providers-provide-2
545564
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-2')
546565
// #docregion providers-provide-3
566+
// Skip for Dart, where the provide() function won't pass type checking.
547567
:marked
548568
The [provide](/docs/ts/latest/api/core/provide-function.html) function is the more common, friendlier way to create a `Provider`:
549569
// #enddocregion providers-provide-3
550570
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-3')
551-
// #docregion providers-provide-4
571+
// #docregion providers-provide-4-1
572+
// Modified for Dart.
552573
:marked
553574
In both approaches &mdash; `Provider` class and `provide` function &mdash;
554575
we supply two arguments.
555-
576+
// #enddocregion providers-provide-4-1
577+
// #docregion providers-provide-4-2
578+
:marked
556579
The first is the [token](#token) that serves as the key for both locating a dependency value
557580
and registering the provider.
558581

559582
The second is a provider definition object,
560583
which we can think of as a *recipe* for creating the dependency value.
561584
There are many ways to create dependency values... and many ways to write a recipe.
562-
// #enddocregion providers-provide-4
585+
// #enddocregion providers-provide-4-2
563586
// #docregion providers-alternative-1
564587
:marked
565588
<a id="class-provider"></a>
@@ -768,9 +791,11 @@ code-example(format, language="html").
768791
// #enddocregion tokens-string-1
769792
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-9a')(format=".")
770793
// #docregion tokens-string-2
794+
- var lang = current.path[1]
795+
- var decorated = lang == 'dart' ? 'annotated' : 'decorated'
771796
:marked
772797
Now we inject the configuration object into any constructor that needs it, with
773-
the help of an `@Inject` decorator that tells Angular how to find the configuration dependency value.
798+
the help of an `@Inject` #{decorator} that tells Angular how to find the configuration dependency value.
774799
// #enddocregion tokens-string-2
775800
+makeExample('dependency-injection/ts/app/providers.component.ts','provider-9a-ctor')(format=".")
776801

0 commit comments

Comments
 (0)