在Typescript中创建AngularJS 1.5组件的最佳做法是什么?

时间:2016-02-17 08:42:27

标签: angularjs typescript angularjs-components

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

似乎最新的方式是在组件中对控制器进行内联编码而不是在单独的文件中编码,并且我可以看到组件样板文件最小的优点。

问题是我将控制器编码为打字稿类,并希望继续这样做,因为这似乎与Angular2一致。

我最大的努力是这样的:

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

}

它有效,但它并不优雅。还有更好的方法吗?

7 个答案:

答案 0 :(得分:35)

如果您想完全采用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 });
};

答案 1 :(得分:32)

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

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--;
  }
}

你可以在http://jsbin.com/jipacoxeki/edit?html,js,output

尝试工作jsbin

答案 2 :(得分:13)

这是我使用的模式:

<强> 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());

答案 3 :(得分:9)

我正在努力解决同样的问题并将我的解决方案放在本文中:

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

&#13;
&#13;
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());

}
&#13;
&#13;
&#13;

答案 4 :(得分:7)

我正在使用以下模式将angular {1.5} component与typescript

一起使用
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: "&"
        }
    });

答案 5 :(得分:1)

我建议不要使用自定义解决方案,而是使用ng-metadata库。您可以在https://github.com/ngParty/ng-metadata找到它。像这样你的代码与Angular 2最兼容。正如自述文件中所述

  

没有黑客。没有覆盖。准备就绪。

我刚从这里的答案中使用自定义解决方案后进行了切换,但如果您立即使用此库,则会更容易。否则,您将必须迁移所有小的语法更改。一个例子是这里的其他解决方案使用语法

@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-metadata recipies复制)

答案 6 :(得分:1)

我认为一种好方法是使用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 {}

如果您想查看使用它的真实应用程序示例,可以查看this one