Hva er beste praksis for å lage en AngularJS 1.5-komponent i Typescript?


Jeg eksperimenterer med .component()-syntaksen i Angular 1.5.

Det ser ut til at den nyeste moten er å kode controlleren direkte i komponenten i stedet for i en egen fil, og jeg kan se fordelen med det gitt at komponentens standardoppsett er minimalt.

Problemet er at jeg har kodet kontrollerne mine som TypeScript-klasser og ønsker å fortsette å gjøre det fordi det ser ut til å være i samsvar med Angular2.

Min beste innsats er noe sånt som dette:

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

}

Det fungerer, men det er ikke elegant. Finnes det en bedre måte?

Svar #1

Hvis du ønsket å fullstendig adoptere en Angular 2-tilnærming, kunne du bruke:

module.ts

import { MyComponent } from './MyComponent';

angular.module('myModule', [])
  .component('myComponent', MyComponent);

MinKomponent.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 });
};

Svar #2

Jeg bruker en enkel Typescript-dekoratør for å lage komponenten

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

så jeg kan bruke det slik

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

Du kan prøve en fungerende jsbin her http://jsbin.com/jipacoxeki/edit?html,js,output

Svar #3

Dette er mønsteret jeg bruker:

ZippyKomponent.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());

Relaterte artikler