closes #1818 Previously, the markdown of some chapters was converted to Jade markup to support the conditional exclusion of TS prose parts in Dart chapters. This commit reverts some of that back to clean markdown, thanks to a few custom directives.
123 lines
4.8 KiB
Plaintext
123 lines
4.8 KiB
Plaintext
extends ../../../ts/latest/guide/dependency-injection.jade
|
|
|
|
block includes
|
|
include ../_util-fns
|
|
- var _thisDot = '';
|
|
|
|
block ctor-syntax
|
|
.l-sub-section
|
|
:marked
|
|
We also leveraged Dart's constructor syntax for declaring parameters and
|
|
initializing properties simultaneously.
|
|
|
|
block injectable-not-always-needed-in-ts
|
|
//- The [Angular 2 Dart Transformer](https://github.com/angular/angular/wiki/Angular-2-Dart-Transformer)
|
|
//- generates static code to replace the use of dart:mirrors. It requires that types be
|
|
//- identified as targets for static code generation. Generally this is achieved
|
|
//- by marking the class as @Injectable (though there are other mechanisms).
|
|
|
|
block always-include-paren
|
|
:marked
|
|
Always write `@Injectable()`, not just `@Injectable`.
|
|
A metadata annotation must be either a reference to a
|
|
compile-time constant variable or a call to a constant
|
|
constructor such as `Injectable()`.
|
|
|
|
If we forget the parentheses, the analyzer will complain:
|
|
"Annotation creation must have arguments". If we try to run the
|
|
app anyway, it won't work, and the console will say
|
|
"expression must be a compile-time constant".
|
|
|
|
block real-logger
|
|
.l-sub-section
|
|
:marked
|
|
A real implementation would probably use the
|
|
[logging package](https://pub.dartlang.org/packages/logging).
|
|
|
|
block provider-ctor-args
|
|
- var _secondParam = 'named parameter, such as <code>useClass</code>'
|
|
:marked
|
|
We supply two arguments (or more) to the `Provider` constructor.
|
|
|
|
block dart-diff-const-metadata
|
|
.callout.is-helpful
|
|
header Dart difference: Constants in metadata
|
|
:marked
|
|
In Dart, the value of a metadata annotation must be a compile-time constant.
|
|
For that reason, we can't call functions to get values
|
|
to use within an annotation.
|
|
Instead, we use constant literals or constant constructors.
|
|
For example, a TypeScript program will use the
|
|
object literal `{ provide: Logger, useClass: BetterLogger }`.
|
|
A Dart annotation would instead use the constant value
|
|
`const Provider(Logger, useClass: BetterLogger)`.
|
|
|
|
block dart-diff-const-metadata-ctor
|
|
.callout.is-helpful
|
|
header Dart difference: Constants in metadata
|
|
:marked
|
|
Because Dart annotations must be compile-time constants,
|
|
`useValue` is often used with string or list literals.
|
|
However, `useValue` works with any constant object.
|
|
|
|
To create a class that can provide constant objects,
|
|
ensure all its instance variables are `final`,
|
|
and give it a `const` constructor.
|
|
|
|
Create a constant instance of the class by using `const` instead of `new`.
|
|
|
|
// - var stylePattern = { otl: /(useValue.*\))/gm };
|
|
// +makeExample('dependency-injection/dart/lib/providers_component.dart','providers-9','', stylePattern)(format='.')
|
|
|
|
block non-class-dep-eg
|
|
span string, list, map, or maybe a function.
|
|
|
|
block config-obj-maps
|
|
| . They can be
|
|
| <b><a href="https://api.dartlang.org/stable/dart-core/Map-class.html">Map</a></b>
|
|
| literals
|
|
|
|
block what-should-we-use-as-token
|
|
:marked
|
|
But what should we use as the token?
|
|
While we _could_ use **[Map][]**, we _should not_ because (like
|
|
`String`) `Map` is too general. Our app might depend on several maps, each
|
|
for a different purpose.
|
|
|
|
[Map]: https://api.dartlang.org/stable/dart-core/Map-class.html
|
|
|
|
.callout.is-helpful
|
|
header Dart difference: Interfaces are valid tokens
|
|
:marked
|
|
In TypeScript, interfaces don't work as provider tokens.
|
|
Dart doesn't have this limitation;
|
|
every class implicitly defines an interface,
|
|
so interface names are just class names.
|
|
`Map` is a *valid* token even though it's the name of an abstract class;
|
|
it's just *unsuitable* as a token because it's too general.
|
|
|
|
block dart-map-alternative
|
|
:marked
|
|
As an alternative to using a configuration `Map`, we can define
|
|
a custom configuration class:
|
|
|
|
+makeExample('dependency-injection/ts/app/app.config.ts','config-alt','app/app-config.ts (alternative config)')(format='.')
|
|
|
|
:marked
|
|
Defining a configuration class has a few benefits. One key benefit
|
|
is strong static checking: we'll be warned early if we misspell a property
|
|
name or assign it a value of the wrong type.
|
|
The Dart [cascade notation][cascade] (`..`) provides a convenient means of initializing
|
|
a configuration object.
|
|
|
|
If we use cascades, the configuration object can't be declared `const` and
|
|
we can't use a [value provider](#value-provider).
|
|
A solution is to use a [factory provider](#factory-provider).
|
|
We illustrate this next. We also show how to provide and inject the
|
|
configuration object in our top-level `AppComponent`:
|
|
|
|
[cascade]: https://www.dartlang.org/docs/dart-up-and-running/ch02.html#cascade
|
|
|
|
+makeExcerpt('lib/app_component.dart','providers')
|
|
+makeExcerpt('lib/app_component.dart','ctor')
|