问题 Angular2中的注射剂


我正在玩Angular2。作为基础,我用了 快速开始 项目来自 angular.io 页。

一切似乎工作正常,但一旦我尝试注入服务(ItemService进入我的 AppComponent 我得到以下异常:

Token(ComponentRef)实例化期间出错! ORIGINAL ERROR:无法解析AppComponent的所有参数。确保它们都具有有效的类型或注释。

我在互联网上看到过类似的问题(例如,包括stackoverflow) 这个帖子),但他们似乎没有解决我的问题。有没有人知道,问题可能是什么?

我也看到了一些解决方案(例如Angular2 repo中的解决方案),它们使用了解决方案来装饰注入类 Injectable-注解。然而,这对我来说不起作用,因为它没有定义 angular.d.ts。我使用的是错误的版本吗?

您可以在以下Plunker中找到我的解决方案: http://plnkr.co/edit/7kK1BtcuEHjaspwLTmsg

为了记录,您还可以在下面找到我的两个文件。请注意 app.js 来自Plunker的是我在下面的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);

提前感谢任何想法!


2615
2018-05-18 19:38


起源



答案:


检查几件事: -

1)确保使用从软件包位置安装的正确版本的typescript(1.5.x)。 ()如果安装了之前版本的typescript,那么仅使用“tsc”命令可以指向环境路径中的现有(<1.5)位置。

2)确保使用 --emitDecoratorMetadata 用tsc命令标记。这是必要的,因此javascript输出为装饰器创建元数据。

3) Error - Cannot read property 'annotations' of undefined   因为 AppComponent 指令依赖于 DetailComponent 还没有定义(到同步时) __decorate( 函数运行以解决依赖关系)以及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);

编辑 

如果您在遵循当前文档方面遇到问题,则从角度a26开始(截至目前) 如果有帮助,请点击此链接 因为有一些相关的变化。


11
2018-05-18 19:58



也注意到你有 ../../ 如果打字是在rootfolder之外的有效打字,但如果它在你的根目录中,你可能想删除一个 ../ - PSL
感谢您的回复。移动定义 DetailComponent 之前 AppComponent 什么都没改变。如果我不使用它就有效 ItemService 但定义了 Items inline,例如在。的构造函数中 AppComponent。它真的与之相关 injectables。打字是在根文件夹之外,所以我想这应该不是问题.. - PzYon
@PzYon因为当我移动它时它对我来说很好。你确定你的文件编译得当吗?我也在使用v23.a。此时我无法访问plunker因此无法真正看到发生了什么...... - PSL
@PzYon查看我的更新... - PSL
感谢您的输入。我担心,我不是TypeScript的专家,但据我所知,它(重新)正确编译,在我的情况下顺序无关紧要。我在Windows上使用TypeScript 1.5 beta在WebStorm中执行。我将以下选项传递给TypeScript编译器: --module "commonjs" --target es5。如果我另外通过 --emitDecoratorMetadata (如angular.io快速入门中所述),我明白了 Error: Cannot start compiler process。也许这就是原因..如果我将我编译的.js文件与你的比较,我可以看到我错过了 __metadata-lines。 - PzYon


答案:


检查几件事: -

1)确保使用从软件包位置安装的正确版本的typescript(1.5.x)。 ()如果安装了之前版本的typescript,那么仅使用“tsc”命令可以指向环境路径中的现有(<1.5)位置。

2)确保使用 --emitDecoratorMetadata 用tsc命令标记。这是必要的,因此javascript输出为装饰器创建元数据。

3) Error - Cannot read property 'annotations' of undefined   因为 AppComponent 指令依赖于 DetailComponent 还没有定义(到同步时) __decorate( 函数运行以解决依赖关系)以及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);

编辑 

如果您在遵循当前文档方面遇到问题,则从角度a26开始(截至目前) 如果有帮助,请点击此链接 因为有一些相关的变化。


11
2018-05-18 19:58



也注意到你有 ../../ 如果打字是在rootfolder之外的有效打字,但如果它在你的根目录中,你可能想删除一个 ../ - PSL
感谢您的回复。移动定义 DetailComponent 之前 AppComponent 什么都没改变。如果我不使用它就有效 ItemService 但定义了 Items inline,例如在。的构造函数中 AppComponent。它真的与之相关 injectables。打字是在根文件夹之外,所以我想这应该不是问题.. - PzYon
@PzYon因为当我移动它时它对我来说很好。你确定你的文件编译得当吗?我也在使用v23.a。此时我无法访问plunker因此无法真正看到发生了什么...... - PSL
@PzYon查看我的更新... - PSL
感谢您的输入。我担心,我不是TypeScript的专家,但据我所知,它(重新)正确编译,在我的情况下顺序无关紧要。我在Windows上使用TypeScript 1.5 beta在WebStorm中执行。我将以下选项传递给TypeScript编译器: --module "commonjs" --target es5。如果我另外通过 --emitDecoratorMetadata (如angular.io快速入门中所述),我明白了 Error: Cannot start compiler process。也许这就是原因..如果我将我编译的.js文件与你的比较,我可以看到我错过了 __metadata-lines。 - PzYon


我的设置:我在Windows上运行WebStorm 10.0.2,使用TypeScript 1.5 beta(编译为ES5)和node / npm。

感谢PSL的帮助,我发现我的设置存在一些问题。 它们与代码无关,例如不是类定义等的顺序 仅仅为了记录,我想总结一下我遇到的问题。大部分都被PSL提及,但也许其他人也有同样的问题,例如:与WebStorm中的编译器相关。

以下是我遇到的问题:

  • 即使我将WebStorm配置为使用通过npm安装的TypeScript 1.5,也使用了旧版本(1.3),因为它也安装在我的系统上(我认为与Visual Studio一起)并在 %path%变量

  • 我将WebStorm配置为使用TypeScript的“自定义编译器版本”(在设置/语言和框架/ TypeScript中),具有以下参数: -emitDecoratorMetadata -m commonjs -t es5 -sourceMap。这有些怎么行不通..我不确定,如果它与WebStorm中的问题有关。没有 -emitDecoratorMetadata 标志它编译,但 injectables 没用。

    [更新,2015年6月9日:是的,它与a有关 问题 在WebStorm]

  • 但是我需要 -emitDecoratorMetadata-flag为了 injectables 在Angular2中工作。

  • 我的解决方案是在WebStorm中添加一个自定义的“文件监视器”(而不是使用“内置编译器”功能),并带有以下参数: -emitDecoratorMetadata -m commonjs -t es5 --sourceMap $FilePath$

使用Angular2,TypeScript 1.5和WebStorm时学到的经验教训:

  • 确保TypeScript 1.5实际上是用于编译ts文件的版本(例如,在IDE中)。

  • 确保 -emitDecoratorMetadata 已指定。

  • 如果按特定顺序或在自己的文件中定义类,则没有区别。  - >订单确实很重要!将类/组件拆分成不同的文件可以解决问题,并且通常会产生更好的可维护文件。

再次感谢PSL的宝贵意见!


3
2018-05-19 16:33



很好的答案。但是我无法理解在你的原始问题中你在定义之前注入DetailsComponent的方式..它应该给出错误 Cannot read property 'annotations' of undefined 这很有意义。因为这条线 directives: [angular2_1.For, angular2_1.If, DetailComponent]之前运行 var DetailComponent = (function () { 这意味着提升变量 DetailComponent  其中包含definision将是未定义的 __decorate 也不是同步的。定义自己的文件并导入它当然会没问题。 - PSL
是的,当然你是对的:订单确实很重要,如果我有可注射的组件,我会得到同样的例外(DetailComponent)在我要注入的组件之后(AppComponent)。我相应地更新了答案。对不起,我很抱歉。 - PzYon
谢谢你确认......我真的不能理解为什么你不会...... :) - PSL


我遇到了同样的问题。以下是决议:

  1. tsc中错过了--emitDecoratorMetadata
  2. 如果我从同一个文件注入服务它失败了,但是当我把服务放到其他文件时,当它被导入时,它就开始工作了。可能是我使用的Angular2版本中的错误。

2
2017-08-01 11:06