Angular2 中的注射剂
Injectables in Angular2
我正在玩 Angular2。作为基础,我使用了 quickstart project from the angular.io 页面。
一切似乎都工作正常,但是当我尝试将服务 (ItemService
) 注入我的 AppComponent
时,我得到以下异常:
Error during instantiation of Token(ComponentRef)!. ORIGINAL ERROR: Cannot resolve all parameters for AppComponent. Make sure they all have valid type or annotations.
我在网上看到过类似的问题(包括Whosebug,例如),但是none似乎解决了我的问题。有没有人知道问题可能是什么?
我也看到了一些解决方案(例如 Angular2 存储库中的解决方案),它们用 Injectable
-注释装饰可注入的 class。但是这对我不起作用,因为它没有在 angular.d.ts
中定义。我使用的版本有误吗?
你可以在下面的 Plunker 中找到我的解决方案:
http://plnkr.co/edit/7kK1BtcuEHjaspwLTmsg
作为记录,您还可以在下面找到我的两个文件。请注意,Plunker 中的 app.js
是从我下面的 TypeScript 文件生成的 JavaScript 文件,异常总是相同的。
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);
提前感谢您的任何想法!
检查几件事:-
1) 确保您使用的是从您的软件包位置安装的正确版本的打字稿 (1.5.x)。 () 如果您安装了以前版本的打字稿,那么仅使用 "tsc" 命令可能会指向环境路径中的现有 (< 1.5) 位置。
2) 确保在 tsc 命令中使用 --emitDecoratorMetadata
标志。这是必要的,因此 javascript 输出会为装饰器创建元数据。
3) Error - Cannot read property 'annotations' of undefined
因为 AppComponent
指令对 DetailComponent
的依赖尚未定义(到同步 __decorate(
函数 运行s 解决依赖关系时)和 TS 编译方式提升变量 DetailComponent
未定义(下面的 IIFE 尚未 运行)。尝试将 DetailComponent
的声明移到 AppComponent
之前。或者只是将其移动到不同的文件并导入它。
@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);
编辑
从 angulara26 开始,如果您在遵循当前文档(截至目前)方面遇到问题,因为有一些相关更改。
我的设置:我是 运行 Windows 上的 WebStorm 10.0.2,使用 TypeScript 1.5 beta(编译为 ES5)和 node/npm。
感谢 PSL 的帮助,我在设置中发现了几个问题。 它们与代码无关,例如不是按照 class 定义等的顺序 只是为了记录,我想总结一下我遇到的问题..其中大部分已经被 PSL 提到,但也许其他人有同样的问题,例如与WebStorm中的编译器相关。
以下是我遇到的问题:
尽管我将 WebStorm 配置为使用通过 npm 安装的 TypeScript 1.5,但使用的是旧版本 (1.3),因为它也安装在我的系统上(我认为连同 Visual Studio ) 并注册在 %path%
变量
我将 WebStorm 配置为对 TypeScript 使用 "Custom Compiler Version"(在 settings/Languages 和 Frameworks/TypeScript 中),参数如下:-emitDecoratorMetadata -m commonjs -t es5 -sourceMap
。这有些不起作用..我不确定它是否与 WebStorm 中的问题有关。没有 -emitDecoratorMetadata
标志它编译,但是 injectables
没有工作。
[更新,2015 年 6 月 9 日:是的,它与 WebStorm 中的一个 issue 有关]
但是我需要 -emitDecoratorMetadata
-flag 才能使 Angular2 中的 injectables
工作。
我的解决方案是在 WebStorm 中添加自定义 "File Watcher"(而不是使用 "builtin Compiler"-函数),参数如下:-emitDecoratorMetadata -m commonjs -t es5 --sourceMap $FilePath$
使用 Angular2、TypeScript 1.5 和 WebStorm 时学到的经验教训:
确保 TypeScript 1.5 确实是用于编译 ts 文件的版本(例如在您的 IDE 中)。
确保指定了 -emitDecoratorMetadata
。
如果 class 是按特定顺序或在自己的文件等中定义的,则没有区别 - > 顺序很重要!将 classes/components 拆分为不同的文件可以解决问题,并且通常会生成更好的可维护文件。
再次感谢 PSL 的宝贵意见!
我遇到过同样的问题。以下是决议:
- --tsc 中缺少 emitDecoratorMetadata
- 如果我从同一个文件注入服务失败,但是当我将服务放入其他文件并导入该文件时,它开始工作了。可能是我使用的 Angular2 版本中的错误。
我正在玩 Angular2。作为基础,我使用了 quickstart project from the angular.io 页面。
一切似乎都工作正常,但是当我尝试将服务 (ItemService
) 注入我的 AppComponent
时,我得到以下异常:
Error during instantiation of Token(ComponentRef)!. ORIGINAL ERROR: Cannot resolve all parameters for AppComponent. Make sure they all have valid type or annotations.
我在网上看到过类似的问题(包括Whosebug,例如
我也看到了一些解决方案(例如 Angular2 存储库中的解决方案),它们用 Injectable
-注释装饰可注入的 class。但是这对我不起作用,因为它没有在 angular.d.ts
中定义。我使用的版本有误吗?
你可以在下面的 Plunker 中找到我的解决方案: http://plnkr.co/edit/7kK1BtcuEHjaspwLTmsg
作为记录,您还可以在下面找到我的两个文件。请注意,Plunker 中的 app.js
是从我下面的 TypeScript 文件生成的 JavaScript 文件,异常总是相同的。
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);
提前感谢您的任何想法!
检查几件事:-
1) 确保您使用的是从您的软件包位置安装的正确版本的打字稿 (1.5.x)。 () 如果您安装了以前版本的打字稿,那么仅使用 "tsc" 命令可能会指向环境路径中的现有 (< 1.5) 位置。
2) 确保在 tsc 命令中使用 --emitDecoratorMetadata
标志。这是必要的,因此 javascript 输出会为装饰器创建元数据。
3) Error - Cannot read property 'annotations' of undefined
因为 AppComponent
指令对 DetailComponent
的依赖尚未定义(到同步 __decorate(
函数 运行s 解决依赖关系时)和 TS 编译方式提升变量 DetailComponent
未定义(下面的 IIFE 尚未 运行)。尝试将 DetailComponent
的声明移到 AppComponent
之前。或者只是将其移动到不同的文件并导入它。
@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);
编辑
从 angulara26 开始,如果您在遵循当前文档(截至目前)方面遇到问题
我的设置:我是 运行 Windows 上的 WebStorm 10.0.2,使用 TypeScript 1.5 beta(编译为 ES5)和 node/npm。
感谢 PSL 的帮助,我在设置中发现了几个问题。 它们与代码无关,例如不是按照 class 定义等的顺序 只是为了记录,我想总结一下我遇到的问题..其中大部分已经被 PSL 提到,但也许其他人有同样的问题,例如与WebStorm中的编译器相关。
以下是我遇到的问题:
尽管我将 WebStorm 配置为使用通过 npm 安装的 TypeScript 1.5,但使用的是旧版本 (1.3),因为它也安装在我的系统上(我认为连同 Visual Studio ) 并注册在
%path%
变量我将 WebStorm 配置为对 TypeScript 使用 "Custom Compiler Version"(在 settings/Languages 和 Frameworks/TypeScript 中),参数如下:
-emitDecoratorMetadata -m commonjs -t es5 -sourceMap
。这有些不起作用..我不确定它是否与 WebStorm 中的问题有关。没有-emitDecoratorMetadata
标志它编译,但是injectables
没有工作。[更新,2015 年 6 月 9 日:是的,它与 WebStorm 中的一个 issue 有关]
但是我需要
-emitDecoratorMetadata
-flag 才能使 Angular2 中的injectables
工作。我的解决方案是在 WebStorm 中添加自定义 "File Watcher"(而不是使用 "builtin Compiler"-函数),参数如下:
-emitDecoratorMetadata -m commonjs -t es5 --sourceMap $FilePath$
使用 Angular2、TypeScript 1.5 和 WebStorm 时学到的经验教训:
确保 TypeScript 1.5 确实是用于编译 ts 文件的版本(例如在您的 IDE 中)。
确保指定了
-emitDecoratorMetadata
。如果 class 是按特定顺序或在自己的文件等中定义的,则没有区别- > 顺序很重要!将 classes/components 拆分为不同的文件可以解决问题,并且通常会生成更好的可维护文件。
再次感谢 PSL 的宝贵意见!
我遇到过同样的问题。以下是决议:
- --tsc 中缺少 emitDecoratorMetadata
- 如果我从同一个文件注入服务失败,但是当我将服务放入其他文件并导入该文件时,它开始工作了。可能是我使用的 Angular2 版本中的错误。