angular - Injicerbara i Angular2
Jag experimenterar med Angular2. Som grund använde jag snabbstartprojektet från angular.io-sidan.
Allting verkar fungera bra, men så fort jag försöker injicera en tjänst (ItemService) i min AppComponent får jag följande undantag:
Fel vid instansiering av Token(ComponentRef)!. URSPRUNGLIGT FEL: Kan inte lösa alla parametrar för AppComponent. Se till att de alla har giltig typ eller annotationer.
Jag har sett liknande problem på internet (inklusive Stack Overflow, till exempel det här inlägget), men inget av dem verkar lösa mitt problem. Har någon någon idé om vad problemet kan vara?
Jag har också sett några lösningar (till exempel de i Angular2-repot) som dekorerar den injicerbara klassen med Injectable-annoteringen. Men detta fungerar inte för mig, eftersom det inte är definierat i angular.d.ts. Använder jag fel version?
Du kan hitta min lösning i följande Plunker: http://plnkr.co/edit/7kK1BtcuEHjaspwLTmsg
För protokollet kan du också hitta mina två filer nedan. Observera att app.js från Plunker är JavaScript-filen som genereras från min TypeScript-fil nedan, undantaget är alltid detsamma.
index.html:
<html>
<head>
<title>Testing Angular2</title>
<script src="https://github.jspm.io/jmcriffey/[email /traceur-runtime.js"></script>
<script src="https://jspm.io/[email "></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);
Tack på förhand för alla idéer!
Svar #1
Kolla ett par saker:-
1) Se till att du använder rätt version av TypeScript (1.5.x) installerad från din paketplats.() Om du har tidigare versioner av TypeScript installerade kan det att använda kommandot "tsc" peka på den befintliga (< 1.5) platsen från miljövägen.
2) Se till att du använder flaggan --emitDecoratorMetadata med tsc-kommandot. Det är nödvändigt så att Javascript-utdata skapar metadata för dekoratörerna.
3) Fel - Kan inte läsa egenskapen 'annotations' av undefined Eftersom AppComponent-direktivet har ett beroende på DetailComponent som ännu inte har definierats (när den synkrona __decorate(-funktionen körs för att lösa beroenden) och sättet TS kompilerar den hoistade variabeln DetailComponent är undefined då (IIFE:n för det nedan har ännu inte körts). Försök flytta deklarationen av DetailComponent före AppComponent. Eller flytta den till en annan fil och importera den.
@Component({
selector: 'item-details',
properties: {
item: "item"
}
})
@View({
template: `<span>You selected {{item.name}}</span>`
})
class DetailComponent {
item:Item;
}
@Component({
selector: 'app',
injectables: [ItemService]
})
@View({
template: `<h1>Testing Angular2</h1>
<ul>
<li *for="#item of items">
{{item.id}}: {{item.name}} |
<a href="#" (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;
return false;
}
}
bootstrap(AppComponent);
Redigera
Från och med Angular a26, om du stöter på problem med att följa den aktuella dokumentationen (för tillfället), följ denna länk om det hjälper eftersom det finns vissa relevanta förändringar.
Svar #2
Min setup: Jag kör WebStorm 10.0.2 på Windows, använder TypeScript 1.5 beta (kompilerat till ES5) och node/npm.
Tack vare PSL:s hjälp upptäckte jag flera problem med min uppsättning. De var inte relaterade till koden, t.ex. inte till ordningen på klassdefinitionerna, etc. Bara för protokollet vill jag sammanfatta de problem jag hade. De flesta av dem har nämnts av PSL, men kanske har andra människor samma problem, t.ex. relaterade till kompilatorn i WebStorm.
Här är de problem jag hade:
Även om jag konfigurerade WebStorm för att använda TypeScript 1.5 installerat via npm, användes en äldre version (1.3), eftersom denna också var installerad på mitt system (jag tror tillsammans med Visual Studio) och registrerad i
%path%-variabelnJag konfigurerade WebStorm för att använda en "Anpassad kompilatorversion" för TypeScript (i inställningar/Språk och ramverk/TypeScript), med följande argument:
-emitDecoratorMetadata -m commonjs -t es5 -sourceMap. Detta fungerar på något sätt inte.. Jag är inte säker på om det är relaterat till ett problem i WebStorm. Utan-emitDecoratorMetadata-flaggan kompilerades det, meninjectablesfungerade inte.[Uppdatering, 9 juni 2015: Ja, det är relaterat till ett problem i WebStorm]
Jag behöver dock
-emitDecoratorMetadata-flaggan för attinjectablesi Angular2 ska fungera.Min lösning var att lägga till en egen "File Watcher" i WebStorm (istället för att använda "inbyggd Compiler"-funktionen) med följande argument:
-emitDecoratorMetadata -m commonjs -t es5 --sourceMap $FilePath$
Lektioner som lärts när man arbetar med Angular2, TypeScript 1.5 och WebStorm:
Se till att TypeScript 1.5 verkligen är den version som används för att kompilera ts-filerna (t.ex. i din IDE).
Se till att
-emitDecoratorMetadataär specificerat.Det spelar ingen roll om klasserna är definierade i en viss ordning eller i egna filer, etc.-> Ordningen spelar roll! Att dela upp klasserna/komponenterna i olika filer löser problemet och leder generellt till mer lättunderhållna filer.
Tack igen till PSL för hans värdefulla insats!
