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

137 lines
5.1 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 service-in-its-own-file
//- N/A
block one-class-per-file-ts-tradeoffs
//- N/A
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 ts-any-decorator-will-do
//- N/A
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 canonical-provider-expr
|  that creates a new instance of the 
a(href="../api/core/Provider-class.html") Provider
|  class:
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')