darKnight
darKnight

Reputation: 6481

Declaring service instance inside constructor in Angular 2

I am new to Angular 2 and Typescript and trying to understand DI. In all the code I have seen, I see that the variable referring to a service is typed into the constructor. Why is that? Why can't we have it declared outside the constructor but inside the class?

Consider following code from the Tour of Heroes e.g. on Angular website:

import { Component, OnInit } from '@angular/core';
import { Hero } from './hero';
import { HeroService } from './hero.service';

@Component({
    moduleId: module.id,
    selector: 'my-dashboard',
    templateUrl: `dashboard.component.html`,
    styleUrls: ['dashboard.component.css']
})
export class DashboardComponent implements OnInit {

    heroes: Hero[] = [];

    constructor(private heroService: HeroService) { }

    ngOnInit(): void {
        this.heroService.getHeroes()
            .then(heroes => this.heroes = heroes.slice(1, 5));
    }
}

If I declare heroService outside the constructor like below, the app throws many errors.

export class DashboardComponent implements OnInit {

    heroes: Hero[] = [];

    constructor() { }

    private heroService: HeroService;

    ngOnInit(): void {
        this.heroService.getHeroes()
            .then(heroes => this.heroes = heroes.slice(1, 5));
    }
}

As I understand, writing it outside the constructor does not generate an instance of the service class HeroService, but why? (Is it a Angular thing or TypeScript?) In this e.g., Hero is also a class (though not a service class, but still technically a class!), and we have declared heroes: Hero[] = []; outside the constructor, and it works.

Upvotes: 5

Views: 4820

Answers (2)

Ilya Chernomordik
Ilya Chernomordik

Reputation: 30195

What you have described here is a property (setter) injection that is in theory possible but is generally not recommended aka considered as a bad practice.

To understand this a little bit better you should read about constructor injection and why it is preferred over other types of injection like property injection.

As far as I know Angular has not implemented other types to force developers to use the best practice, that's why you cannot use it outside of the constructor.

Angular 1 references this doc that you can read to understand it deeper. Don't worry that it is from previous version, these are conceptual terms that are irrelevant to the framework or language, so you can read it to understand the basics.

P.S. Don't forget that having a variable in constructor the way you have it in Typescript (with private) will automatically create a property. So when you have it in a constructor, Angular injects it there and Typescripts implicitly creates a field as in your last snippet and initializes it from the constructor parameter.

Upvotes: 2

Günter Zöchbauer
Günter Zöchbauer

Reputation: 657188

Angular DI inspects the constructor parameters and when Angular DI creates a new instance of a class (service, component, directive, pipe), it looks up matching providers to be passed to the constructor.

Therefore,

  • injection only works for classed instantiated by DI

  • only constructor parameters are considered for injection

Upvotes: 3

Related Questions