Angular 2 service injection using TypeScript 1.5

2.6k Views Asked by At

I'm trying to get a very basic, functional structure set up for Angular 2. It will have only the most basic API elements so that as the framework advances, I can advance my structure.

Currently, I'm at my wit's end as to how to perform the simple act of passing services. Here is some example source, taken right from the comments of the most recent DefinitelyTyped file:

class Greeter {
    greet(name: string) {
        return 'Hello ' + name + '!';
    }
}
@Component({
    selector: 'greet',
    appInjector: [Greeter]
})
@View({
    template: `{{greeter.greet('world')}}!`
})
class HelloWorld {
    greeter: Greeter;
    constructor(greeter: Greeter) {
        this.greeter = greeter;
    }
}
bootstrap(HelloWorld);

As you can see, I'm using Typescript 1.5 in this example.

I have tried to inject the Greeting service in the Component annotation using hostInjector, injectibles and appInjector. I've also tried adding it to the second argument of the bootstrap call, as in bootstrap(HelloWorld, [Greeter]).

In all cases I get this error message when trying to run it in the browser:

Error during instantiation of Token(ComponentRef)!. ORIGINAL ERROR: Cannot resolve all parameters for HelloWorld(?). Make sure they all have valid type or annotations.

Of course, if I remove greeter: Greeter argument from the constructor, the error in question goes away and is replaced by other, expected errors further down the chain.

Ideas?

EDIT

I updated the title of this question to specify that I am using TypeScript 1.5

6

There are 6 best solutions below

4
On

Here is the code, straight out of the plnkr.co template for injecting a service http://plnkr.co/edit/m5sHWWFmgYPrfsMv0u2r

import {
  ComponentAnnotation as Component,
  ViewAnnotation as View, bootstrap
} from 'angular2/angular2';

@Component({
  selector: 'app',
  viewInjector: [Service]
})
@View({
  template: '{{greeting}} world!'
})
class App {
  constructor(service: Service) {
    this.greeting = service.greeting();
    setTimeout(() => this.greeting = 'Howdy,', 1000);
  }
}

class Service {
  greeting() {
    return 'Hello';
  }
}

bootstrap(App);
1
On

Regarding TS2348. I got the same error. Got rid of ComponentAnnotaion and ViewAnnotation and this helped:

import {
  bootstrap,
  Component,
  View
} from 'angular2/angular2';
1
On

I had a similar problem when using typescript 1.5.0-beta and angular 2.0.0-alpha.28 (not sure if the versions are strictly relevant) with gulp.

You need to tell the typescript compiler to export metadata so the DI injector knows what to do. I did this by adding emitDecoratorMetadata and experimentalDecorators to my tsconfig.json:

{
    "compilerOptions": {
        "module": "commonjs",
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "sourceMap": true,
        "target": "es5"
    }
}

After that you can add appInjector: [Greeter] to your @Component declaration like you've done or to the bootstrap declaration:

bootstrap(HelloWorld, [Greeter]);
1
On

With angular2.0.0-alpha.32 I accomplished this with

/// <reference path="../../typings/angular2/angular2.d.ts" />

import {Component, View, bootstrap, NgFor} from 'angular2/angular2';
import {MyService} from 'js/services/MyService';

// Annotation section
@Component({
    selector: 'my-app',
    viewInjector: [MyService]
})
@View({
    templateUrl: 'templates/my-app.tpl.html',
    directives: [NgFor]
})

class MyComponent {
    mySvc:MyService;

    constructor(mySvc:MyService) {
        this.mySvc = mySvc;
    }

    onInit() {
        this.mySvc.getData();
    }
}   

bootstrap(MyComponent, [MyService]);
2
On

More a workaround than a solution, but if you move your service definition to a separate file (greeting.ts), and import it

import {Greeting} from 'greeting';

then the injector works correctly. This is built using tsc from the command line (taken from the 5 min quickstart on angular.io)

tsc --watch -m commonjs -t es5 --emitDecoratorMetadata  app.ts
1
On

I hope your code will work fine in typescript 1.5 release. Right now, you should use Inject annotation in typescript 1.5.0-beta.

import {
  ComponentAnnotation as Component,
  ViewAnnotation as View, bootstrap,
  Inject
} from 'angular2/angular2';

@Component({
  selector: 'app',
  hostInjector: [Service]
})
@View({
  template: '{{greeting}} world!'
})
class App {
  constructor(@Inject(Service)service: Service) {
    this.greeting = service.greeting();
    setTimeout(() => this.greeting = 'Howdy,', 1000);
  }
}

class Service {
  greeting() {
    return 'Hello';
  }
}

bootstrap(App);