在Typescript中创build一个AngularJS 1.5组件的最佳实践是什么?

我正在使用Angular 1.5中的.component()语法进行试验。

看起来,最新的方式是在组件中编码控制器,而不是单独的文件,我可以看到,鉴于组件样板是最小的优点。

问题是我一直编写我的控制器作为打字稿类,并希望继续这样做,因为这似乎是符合Angular2。

我最大的努力就是这样的:

 export let myComponent = { template: ($element, $attrs) => { return [ `<my-html>Bla</my-html>` ].join('') }, controller: MyController }; class MyController { } 

它的工作,但它不是优雅的。 有没有更好的办法?

如果你想完全采用Angular 2的方法,你可以使用:

module.ts

 import { MyComponent } from './MyComponent'; angular.module('myModule', []) .component('myComponent', MyComponent); 

MyComponent.ts

 import { Component } from './decorators'; @Component({ bindings: { prop: '<' }, template: '<p>{{$ctrl.prop}}</p>' }) export class MyComponent { prop: string; constructor(private $q: ng.IQService) {} $onInit() { // do something with this.prop or this.$q upon initialization } } 

decorators.ts

 /// <reference path="../typings/angularjs/angular.d.ts" /> export const Component = (options: ng.IComponentOptions) => { return controller => angular.extend(options, { controller }); }; 

我正在使用一个简单的Typescript装饰器来创build组件

 function Component(moduleOrName: string | ng.IModule, selector: string, options: { controllerAs?: string, template?: string, templateUrl?: string }) { return (controller: Function) => { var module = typeof moduleOrName === "string" ? angular.module(moduleOrName) : moduleOrName; module.component(selector, angular.extend(options, { controller: controller })); } } 

所以我可以像这样使用它

 @Component(app, 'testComponent', { controllerAs: 'ct', template: ` <pre>{{ct}}</pre> <div> <input type="text" ng-model="ct.count"> <button type="button" ng-click="ct.decrement();">-</button> <button type="button" ng-click="ct.increment();">+</button> </div> ` }) class CounterTest { count = 0; increment() { this.count++; } decrement() { this.count--; } } 

你可以尝试一个工作jsbin在这里http://jsbin.com/jipacoxeki/edit?html,js,output

这是我使用的模式:

ZippyComponent.ts

 import {ZippyController} from './ZippyController'; export class ZippyComponent implements ng.IComponentOptions { public bindings: { bungle: '<', george: '<' }; public transclude: boolean = false; public controller: Function = ZippyController; public controllerAs: string = 'vm'; public template: string = require('./Zippy.html'); } 

ZippyController.ts

 export class ZippyController { bungle: string; george: Array<number>; static $inject = ['$timeout']; constructor (private $timeout: ng.ITimeoutService) { } } 

Zippy.html

 <div class="zippy"> {{vm.bungle}} <span ng-repeat="item in vm.george">{{item}}</span> </div> 

main.ts

 import {ZippyComponent} from './components/Zippy/ZippyComponent'; angular.module('my.app', []) .component('myZippy', new ZippyComponent()); 

我正在同样的问题挣扎,并把我的解决scheme放在这篇文章中:

http://almerosteyn.github.io/2016/02/angular15-component-typescript

 module app.directives { interface ISomeComponentBindings { textBinding: string; dataBinding: number; functionBinding: () => any; } interface ISomeComponentController extends ISomeComponentBindings { add(): void; } class SomeComponentController implements ISomeComponentController { public textBinding: string; public dataBinding: number; public functionBinding: () => any; constructor() { this.textBinding = ''; this.dataBinding = 0; } add(): void { this.functionBinding(); } } class SomeComponent implements ng.IComponentOptions { public bindings: any; public controller: any; public templateUrl: string; constructor() { this.bindings = { textBinding: '@', dataBinding: '<', functionBinding: '&' }; this.controller = SomeComponentController; this.templateUrl = 'some-component.html'; } } angular.module('appModule').component('someComponent', new SomeComponent()); } 

我正在使用以下模式与打字稿使用angular​​1.5 组件

 class MyComponent { model: string; onModelChange: Function; /* @ngInject */ constructor() { } modelChanged() { this.onModelChange(this.model); } } angular.module('myApp') .component('myComponent', { templateUrl: 'model.html', //template: `<div></div>`, controller: MyComponent, controllerAs: 'ctrl', bindings: { model: '<', onModelChange: "&" } }); 

我build议不要使用定制的解决scheme,而是使用ng-metadata库来代替。 你可以在https://github.com/ngParty/ng-metadatafind它。; 像这样你的代码是最适合Angular 2的。 正如在自述中所述的那样

没有黑客。 没有覆盖。 生产准备。

我刚从这个答案中使用了一个自定义的解决scheme之后切换,但是如果您立即使用这个库,则会更容易。 否则,你将不得不迁移所有小的语法变化。 一个例子是这里的其他解决scheme使用语法

 @Component('moduleName', 'selectorName', {...}) 

而Angular 2使用

 @Component({ selector: ..., ... }) 

所以,如果你不使用ng-metadata ,你将会大大增加后面你的代码库的迁移工作。

编写组件的最佳实践的完整示例如下

 // hero.component.ts import { Component, Inject, Input, Output, EventEmitter } from 'ng-metadata/core'; @Component({ selector: 'hero', moduleId: module.id, templateUrl: './hero.html' }) export class HeroComponent { @Input() name: string; @Output() onCall = new EventEmitter<void>(); constructor(@Inject('$log') private $log: ng.ILogService){} } 

(从ng元数据收件复制)

我相信一个好方法是使用angular-ts-decorators 。 有了它,你可以像这样在AngularJS中定义组件:

 import { Component, Input, Output } from 'angular-ts-decorators'; @Component({ selector: 'myComponent', templateUrl: 'my-component.html }) export class MyComponent { @Input() todo; @Output() onAddTodo; $onChanges(changes) { if (changes.todo) { this.todo = {...this.todo}; } } onSubmit() { if (!this.todo.title) return; this.onAddTodo({ $event: { todo: this.todo } }); } } 

然后使用以下命令将它们注册到模块中:

 import { NgModule } from 'angular-ts-decorators'; import { MyComponent } from './my-component'; @NgModule({ declarations: [MyComponent] }) export class MyModule {} 

如果你想检查一个真正的应用程序使用它的例子,你可以检查这一个 。