angular-cn/public/docs/dart/latest/guide/dependency-injection.jade
Patrice Chalin b0e0d94b5c docs: revert Jade to markdown
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.
2016-07-05 23:03:30 -07:00

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')