Инъекции в Angular2
Я играю с Angular2. В качестве основы я использовал проект quickstart из angular.io.
Все работает нормально, но как только я пытаюсь ввести службу (ItemService
) в мой AppComponent
, я получаю следующее исключение:
Ошибка при создании Token (ComponentRef)!. ОРИГИНАЛЬНАЯ ОШИБКА. Невозможно разрешить все параметры для AppComponent. Убедитесь, что все они имеют допустимый тип или аннотации.
Я видел похожие проблемы в Интернете (включая stackoverflow, например этот пост), но ни один из них, похоже, не решил мою проблему. Есть ли какие-либо идеи, какая проблема может быть?
Я также видел некоторые решения (например, те, что были в репо Angular2), которые украшают класс для инъекций с помощью Injectable
-nnotation. Однако это не работает для меня, поскольку это не определено в angular.d.ts
. Я использую неправильную версию?
Вы можете найти мое решение в следующем Plunker:
http://plnkr.co/edit/7kK1BtcuEHjaspwLTmsg
Для записи вы также можете найти мои два файла ниже. Обратите внимание, что app.js
из Plunker - это файл JavaScript, созданный из моего файла TypeScript ниже, исключение всегда одно и то же.
index.html
:
<html>
<head>
<title>Testing Angular2</title>
<script src="https://github.jspm.io/jmcriffey/[email protected]/traceur-runtime.js"></script>
<script src="https://jspm.io/[email protected]"></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) Убедитесь, что вы используете правильную версию 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
равен undefined, тогда (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);
Изменить
По состоянию на angular a26, если вы столкнулись с проблемами в отношении выполнения текущей документации (на данный момент) следуйте этой ссылке, если это помогает, поскольку там некоторые соответствующие изменения.
Ответ 2
Моя настройка: я запускаю WebStorm 10.0.2 в Windows, используя TypeScript 1.5 beta (скомпилированный в ES5) и node/npm.
Благодаря помощи PSL я обнаружил несколько проблем с моей настройкой. Они не были связаны с кодом, например. а не по порядку определений классов и т.д. Только для записи я хотел бы обобщить проблемы, которые у меня были. Большинство из них упоминалось в PSL, но, возможно, у других людей есть те же проблемы, например. связанные с компилятором в WebStorm.
Вот проблемы, которые у меня были:
-
Несмотря на то, что я настроил WebStorm на использование TypeScript 1.5, установленного через npm, использовалась старая версия (1.3), поскольку она также была установлена в моей системе (я думаю, вместе с Visual Studio) и зарегистрирована в %path%
variable
-
Я настроил WebStorm на использование "Custom Compiler Version" для TypeScript (в настройках/Языки и Frameworks/TypeScript) со следующими аргументами: -emitDecoratorMetadata -m commonjs -t es5 -sourceMap
. Некоторые из них не работают. Я не уверен, если это связано с проблемой в WebStorm. Без флага -emitDecoratorMetadata
он скомпилирован, но injectables
не работает.
[Обновление, 9. Июнь 2015: Да, это связано с issue в WebStorm]
-
Однако мне нужен -emitDecoratorMetadata
-flag, чтобы injectables
в Angular2 работал.
-
Моим решением было добавить пользовательский "Наблюдатель файлов" в WebStorm (вместо использования встроенной функции компилятора) со следующими аргументами: -emitDecoratorMetadata -m commonjs -t es5 --sourceMap $FilePath$
Уроки, извлеченные при работе с Angular2, TypeScript 1.5 и WebStorm:
-
Убедитесь, что TypeScript 1.5 действительно версия, которая используется для компиляции файлов ts (например, в вашей среде IDE).
-
Убедитесь, что указан -emitDecoratorMetadata
.
-
Это не имеет значения, если классы определены в определенном порядке или в собственных файлах и т.д. → Заказ имеет значение! Разделение классов/компонентов на разные файлы решает проблему и, как правило, приводит к лучшим файлам, поддерживающим maintanable.
Еще раз спасибо PSL за его ценный вклад!
Ответ 3
У меня была та же проблема. Ниже была резолюция:
- - emitDecoratorMetadata был пропущен в tsc
- Если я вводил службу из того же файла, она терпела неудачу, но когда я помещал эту услугу в какой-то другой файл, и когда она была импортирована, она начала работать. вероятно, ошибка в версии Angular2, которую я использовал.