137 lines
5.1 KiB
Plaintext
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')
|