I am playing around with Angular2. As a basis, I used the quickstart project from the angular.io page.
Everything seems to work fine, but as soon as I try to inject a service (ItemService
) into my AppComponent
I get following exception:
Error during instantiation of Token(ComponentRef)!. ORIGINAL ERROR: Cannot resolve all parameters for AppComponent. Make sure they all have valid type or annotations.
I have seen similar issues on the internet (including stackoverflow, for example this post), but none of them seem to solve my problem. Does any body have any idea, what the problem could be?
I have also seen some solutions (for example the ones in the Angular2 repo) which decorate the injectable class with the Injectable
-annotation. However this doesn't work for me, as it is not defined in angular.d.ts
. Am I using a wrong version?
You can find my solution in following Plunker: http://plnkr.co/edit/7kK1BtcuEHjaspwLTmsg
For the record, you can also find my two files below. Please note that the app.js
from the Plunker is the JavaScript file generated out of my TypeScript file below, the exception is always the same.
index.html
:
<html>
<head>
<title>Testing Angular2</title>
<script src="https://github.jspm.io/jmcriffey/bower-traceur-runtime@0.0.87/traceur-runtime.js"></script>
<script src="https://jspm.io/system@0.16.js"></script>
<script src="https://code.angularjs.org/2.0.0-alpha.23/angular2.dev.js"></script>
</head>
<body>
<app></app>
<script>
System.import('js/app');
</script>
</body>
</html>
js/app.ts
:
/// <reference path="../../typings/angular2/angular2.d.ts" />
import {Component, View, bootstrap, For, If} from "angular2/angular2";
class Item {
id:number;
name:string;
constructor(id:number, name:string) {
this.id = id;
this.name = name;
}
}
class ItemService {
getItems() {
return [
new Item(1, "Bill"),
new Item(2, "Bob"),
new Item(3, "Fred")
];
}
}
@Component({
selector: 'app',
injectables: [ItemService]
})
@View({
template: `<h1>Testing Angular2</h1>
<ul>
<li *for="#item of items">
{{item.id}}: {{item.name}} |
<a href="javascript:void(0);" (click)="toggleSelected(item);">
{{selectedItem == item ? "unselect" : "select"}}
</a>
</li>
</ul>
<item-details *if="selectedItem" [item]="selectedItem"></item-details>`,
directives: [For, If, DetailComponent]
})
class AppComponent {
items:Item[];
selectedItem:Item;
constructor(itemService:ItemService) {
this.items = itemService.getItems();
}
toggleSelected(item) {
this.selectedItem = this.selectedItem == item ? null : item;
}
}
@Component({
selector: 'item-details',
properties: {
item: "item"
}
})
@View({
template: `<span>You selected {{item.name}}</span>`
})
class DetailComponent {
item:Item;
}
bootstrap(AppComponent);
Thanks in advance for any ideas!
My setup: I am running WebStorm 10.0.2 on Windows, using TypeScript 1.5 beta (compiled to ES5) and node/npm.
Thanks to PSL's help, I found several problems with my setup.
They were not related to the code, e.g. not to the order of the class definitions, etc.Just for the record I would like to summarize the issues I had.. Most of them have been mentioned by PSL, but maybe other people have the same problems, e.g. related to the compiler in WebStorm.Here are the problems I had:
Even though I configured WebStorm to use TypeScript 1.5 installed via npm, an old version (1.3) was used, as this was also installed on my system (I think together with Visual Studio) and registered in the
%path%
variableI configured WebStorm to use a "Custom Compiler Version" for TypeScript (in settings/Languages and Frameworks/TypeScript), with following arguments:
-emitDecoratorMetadata -m commonjs -t es5 -sourceMap
. This some how doesn't work.. I'm not sure, if it is related to an issue in WebStorm. Without the-emitDecoratorMetadata
flag it compiled, but theinjectables
didn't work.[Update, 9. June 2015: Yes, it is related to an issue in WebStorm]
However I need the
-emitDecoratorMetadata
-flag in order for theinjectables
in Angular2 to work.My solution was to add a custom "File Watcher" in WebStorm (instead of using the "builtin Compiler"-function) with following arguments:
-emitDecoratorMetadata -m commonjs -t es5 --sourceMap $FilePath$
Lessons learned when working with Angular2, TypeScript 1.5 and WebStorm:
Ensure TypeScript 1.5 is really the version which is used to compile the ts files (e.g. in your IDE).
Ensure the
-emitDecoratorMetadata
is specified.It doesn't make a difference, if the classes are defined in a specific order or in own files, etc.-> Order does matter! Splitting the classes/components into different files solves the problem and generally leads to better maintanable files.Thanks again to PSL for his valuable input!
I had faced the same problem. Below were the resolution:
Check for couple of things:-
1) Make sure you are using the correct version of typescript (1.5.x) installed from your package location. () If you have previous versions of typescript installed then merely using "tsc" command could be pointing to the existing (< 1.5) location from the environment path.
2) Make sure you use
--emitDecoratorMetadata
flag with the tsc command. It is necessary so the javascript output creates the metadata for the decorators.3)
Error - Cannot read property 'annotations' of undefined
BecauseAppComponent
directive has a dependency onDetailComponent
which has not been defined yet (by the time the synchronous__decorate(
function runs to resolve the dependencies) and the way TS compiles the hoisted variableDetailComponent
is undefined then (The IIFE for that below is yet to run). Try moving the declaration ofDetailComponent
beforeAppComponent
. Or just move it to a different file and import it.Edit
As of angular a26 if you face issues with respect to following the current documentation (as of now) follow this link if it helps as there are some relevant changes.