include ../_util-fns +includeShared('{ts}', 'intro') :marked The complete source code for the example app in this chapter is [in GitHub](https://github.com/angular/angular.io/tree/master/public/docs/_examples/dependency-injection/dart). +includeShared('{ts}', 'why-1') +makeExample('dependency-injection/dart/lib/car/car_no_di.dart', 'car', 'lib/car/car.dart (without DI)') +includeShared('{ts}', 'why-2') +makeTabs( 'dependency-injection/dart/lib/car/car.dart, dependency-injection/dart/lib/car/car_no_di.dart', 'car-ctor, car-ctor', 'lib/car/car.dart (excerpt with DI), lib/car/car.dart (excerpt without DI)')(format=".") +includeShared('{ts}', 'why-3-1') +includeShared('{ts}', 'why-3-2') - var stylePattern = { otl: /(new Car.*$)/gm }; +makeExample('dependency-injection/dart/lib/car/car_creations.dart', 'car-ctor-instantiation', '', stylePattern)(format=".") +includeShared('{ts}', 'why-4') .l-sub-section :marked The _consumer_ of `Car` has the problem. The consumer must update the car creation code to something like this: - var stylePattern = { otl: /(new Car.*$)/gm }; +makeExample('dependency-injection/dart/lib/car/car_creations.dart', 'car-ctor-instantiation-with-param', '', stylePattern)(format=".") :marked The critical point is this: `Car` itself did not have to change. We'll take care of the consumer's problem soon enough. +includeShared('{ts}', 'why-6') - var stylePattern = { otl: /(new Car.*$)/gm }; +makeExample('dependency-injection/dart/lib/car/car_creations.dart', 'car-ctor-instantiation-with-mocks', '', stylePattern)(format=".") +includeShared('{ts}', 'why-7') +makeExample('dependency-injection/dart/lib/car/car_factory.dart', null, 'lib/car/car_factory.dart') +includeShared('{ts}', 'why-8') +makeExample('dependency-injection/dart/lib/car/car_injector.dart','injector-call')(format=".") +includeShared('{ts}', 'why-9') +includeShared('{ts}', 'di-1') +makeTabs( `dependency-injection/dart/lib/heroes/heroes_component_1.dart, dependency-injection/dart/lib/heroes/hero_list_component_1.dart, dependency-injection/dart/lib/heroes/hero.dart, dependency-injection/dart/lib/heroes/mock_heroes.dart`, 'v1,,,', `lib/heroes/heroes_component.dart, lib/heroes/hero_list_component.dart, lib/heroes/hero.dart, lib/heroes/mock_heroes.dart`) +includeShared('{ts}', 'di-2') +includeShared('{ts}', 'di-3') +makeExample('dependency-injection/dart/lib/heroes/hero_service_1.dart',null, 'lib/heroes/hero_service.dart' ) +includeShared('{ts}', 'di-4') .l-sub-section :marked We aren't even pretending this is a real service. If we were actually getting data from a remote server, the API would have to be asynchronous, returning a `Future`. We'd also have to rewrite the way components consume our service. This is important in general, but not to our current story. +includeShared('{ts}', 'di-6') +includeShared('{ts}', 'di-configure-injector-1') +makeExample('dependency-injection/dart/web/main.dart', 'bootstrap', 'web/main.dart (excerpt)')(format='.') +includeShared('{ts}', 'di-configure-injector-2') +makeExample('dependency-injection/dart/web/main_1.dart', 'bootstrap')(format='.') +includeShared('{ts}', 'di-configure-injector-3') +includeShared('{ts}', 'di-register-providers-1') +makeExample('dependency-injection/dart/lib/heroes/heroes_component_1.dart',null,'lib/heroes/heroes_component.dart') +includeShared('{ts}', 'di-register-providers-2') +makeExample('dependency-injection/dart/lib/heroes/heroes_component_1.dart','providers')(format='.') +includeShared('{ts}', 'di-register-providers-3') +includeShared('{ts}', 'di-prepare-for-injection-1') +makeTabs( `dependency-injection/dart/lib/heroes/hero_list_component_2.dart, dependency-injection/dart/lib/heroes/hero_list_component_1.dart`, null, `lib/heroes/hero_list_component (with DI), lib/heroes/hero_list_component (without DI)`) .l-sub-section :marked ### Focus on the constructor Adding a parameter to the constructor isn't all that's happening here. +makeExample('dependency-injection/dart/lib/heroes/hero_list_component_2.dart', 'ctor')(format=".") :marked The constructor parameter has a type: `HeroService`. The `HeroListComponent` class is also annotated with `@Component` (scroll up to confirm that fact). Also recall that the parent component (`HeroesComponent`) has `providers` information for `HeroService`. The constructor parameter type, the `@Component` annotation, and the parent's `providers` information combine to tell the Angular injector to inject an instance of `HeroService` whenever it creates a new `HeroListComponent`. +includeShared('{ts}', 'di-create-injector-implicitly-1') +makeExample('dependency-injection/dart/lib/car/car_injector.dart','injector-create-and-call')(format=".") +includeShared('{ts}', 'di-create-injector-implicitly-2') +includeShared('{ts}', 'di-singleton-services') // Skip the testing section, for now. // includeShared('{ts}', 'di-testing-component-1') // includeShared('{ts}', 'di-testing-component-2') +includeShared('{ts}', 'di-service-service-1') +makeTabs( `dependency-injection/dart/lib/heroes/hero_service_2.dart, dependency-injection/dart/lib/heroes/hero_service_1.dart`, null, `lib/heroes/hero_service (v.2), lib/heroes/hero_service (v.1)`) +includeShared('{ts}', 'di-service-service-2') +includeShared('{ts}', 'di-injectable-1') :marked Forgetting the `@Injectable()` can cause a runtime error: code-example(format, language="html"). Cannot find reflection information on <Type> +includeShared('{ts}', 'di-injectable-2') .callout.is-critical header Always include the parentheses :marked Always use `@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". +includeShared('{ts}', 'logger-service-1') +makeExample( 'dependency-injection/dart/lib/logger_service.dart',null, 'lib/logger_service') .l-sub-section :marked ### Implementing a logger Our examples use a simple logger. A real implementation would probably use the [logging package](https://pub.dartlang.org/packages/logging). :marked We're likely to need the same logger service everywhere in our application, so we put it in the `lib/` folder, and we register it in the `providers` array of the metadata for our application root component, `AppComponent`. +makeExample('dependency-injection/dart/lib/providers_component.dart','providers-logger', 'lib/app_component.dart (excerpt)') +includeShared('{ts}', 'logger-service-3') +includeShared('{ts}', 'logger-service-4') +includeShared('{ts}', 'logger-service-5') +makeExample('dependency-injection/dart/lib/providers_component.dart','provider-10-ctor')(format='.') +includeShared('{ts}', 'logger-service-6') +makeExample('dependency-injection/dart/lib/providers_component.dart','provider-10-logger')(format='.') +includeShared('{ts}', 'logger-service-7') +includeShared('{ts}', 'providers-1') +makeExample('dependency-injection/dart/lib/providers_component.dart','providers-logger') +includeShared('{ts}', 'providers-2') +includeShared('{ts}', 'providers-provide-1') :marked ### The *Provider* class +includeShared('{ts}', 'providers-provide-1-1') +makeExample('dependency-injection/dart/lib/providers_component.dart','providers-1') +includeShared('{ts}', 'providers-provide-2') +makeExample('dependency-injection/dart/lib/providers_component.dart','providers-2') // includeShared('{ts}', 'providers-provide-3') // includeShared('{ts}', 'providers-provide-4-1') // Don't discuss provide function. :marked We supply two arguments (or more) to the `Provider` constructor. +includeShared('{ts}', 'providers-provide-4-2') :marked The second is a named parameter, such as `useClass`, that we can think of as a *recipe* for creating the dependency value. There are many ways to create dependency values... and many ways to write a recipe. +includeShared('{ts}', 'providers-alternative-1') +makeExample('dependency-injection/dart/lib/providers_component.dart','providers-4') .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 might use the function call `provide(Logger, {useClass: BetterLogger})`, which is equivalent to the TypeScript code `new Provider(Logger, {useClass: BetterLogger})`. A Dart annotation would instead use the constant value `const Provider(Logger, useClass: BetterLogger)`. +includeShared('{ts}', 'providers-alternative-2') +makeExample('dependency-injection/dart/lib/providers_component.dart','EvenBetterLogger') +includeShared('{ts}', 'providers-alternative-3') +makeExample('dependency-injection/dart/lib/providers_component.dart','providers-5')(format=".") +includeShared('{ts}', 'providers-aliased-1') +makeExample('dependency-injection/dart/lib/providers_component.dart','providers-6a')(format=".") +includeShared('{ts}', 'providers-aliased-2') - var stylePattern = { otl: /(useExisting.*\))/gm }; +makeExample('dependency-injection/dart/lib/providers_component.dart','providers-6b','', stylePattern)(format=".") +includeShared('{ts}', 'providers-value-1') :marked We can provide objects directly, instead of asking the injector to create an instance of a class, by specifying a `useValue` parameter to `Provider`. 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, make sure all its instance variables are `final`, and give it a `const` constructor: +makeExample('dependency-injection/dart/lib/app_config.dart','const-class','lib/app_config.dart (excerpt)')(format='.') :marked Create a constant instance of the class by using `const` instead of `new`: +makeExample('dependency-injection/dart/lib/app_config.dart','const-object','lib/app_config.dart (excerpt)')(format='.') :marked Then specify the object using the `useValue` argument to `Provider`: - var stylePattern = { otl: /(useValue.*\))/gm }; +makeExample('dependency-injection/dart/lib/providers_component.dart','providers-9','', stylePattern)(format='.') :marked See more `useValue` examples in the [Non-class dependencies](#non-class-dependencies) and [OpaqueToken](#opaquetoken) sections. +includeShared('{ts}', 'providers-factory-1') +makeExample('dependency-injection/dart/lib/heroes/hero_service.dart','internals', 'lib/heroes/hero_service.dart (excerpt)')(format='.') +includeShared('{ts}', 'providers-factory-2') +makeExample('dependency-injection/dart/lib/heroes/hero_service_provider.dart','factory', 'lib/heroes/hero_service_provider.dart (excerpt)')(format='.') +includeShared('{ts}', 'providers-factory-3') +makeExample('dependency-injection/dart/lib/heroes/hero_service_provider.dart','provider', 'lib/heroes/hero_service_provider.dart (excerpt)')(format='.') +includeShared('{ts}', 'providers-factory-4') +includeShared('{ts}', 'providers-factory-5') - var stylePattern = { otl: /(providers.*),$/gm }; +makeTabs( `dependency-injection/dart/lib/heroes/heroes_component.dart, dependency-injection/dart/lib/heroes/heroes_component_1.dart`, null, `lib/heroes/heroes_component (v.3), lib/heroes/heroes_component (v.2)`, stylePattern) +includeShared('{ts}', 'tokens-1') +makeExample('dependency-injection/dart/lib/injector_component.dart','get-hero-service')(format='.') +includeShared('{ts}', 'tokens-2') // [PENDING: How about a better name than ProviderComponent8?] +makeExample('dependency-injection/dart/lib/providers_component.dart','provider-8-ctor')(format=".") +includeShared('{ts}', 'tokens-3') .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 problem; every class implicitly defines an interface, so interface names are just class names. +includeShared('{ts}', 'tokens-non-class-deps-1') :marked We know we can register an object with a [value provider](#value-provider). But what do we use for the token? +includeShared('{ts}', 'tokens-opaque-1') +makeExample('dependency-injection/dart/lib/providers_component.dart','opaque-token')(format='.') +includeShared('{ts}', 'tokens-opaque-2') +makeExample('dependency-injection/dart/lib/providers_component.dart','use-opaque-token')(format=".") :marked Here's an example of providing configuration information for an injected class. First define the class: +makeExample('dependency-injection/dart/lib/providers_component.dart','configurable-logger')(format=".") :marked Then inject that class and its configuration information: +makeExample('dependency-injection/dart/lib/providers_component.dart','providers-7')(format=".") +includeShared('{ts}', 'summary') +includeShared('{ts}', 'appendix-explicit-injector-1') +makeExample('dependency-injection/dart/lib/injector_component.dart', 'injector', 'lib/injector_component.dart') +includeShared('{ts}', 'appendix-explicit-injector-2')