Angular 1.5。)で.component()
構文を試しています。
最新の方法は、別個のファイルではなく、コンポーネントでコントローラーをインラインでコーディングすることであるように思われます。
問題は、コントローラーをTypeScriptクラスとしてコーディングしており、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デコレータを使用してコンポーネントを作成しています
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());
私は同じ質問に苦労していたので、この記事に私の解決策を入れました。
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());
}
TypeScriptでangular 1.5 component を使用するために次のパターンを使用しています
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: "&"
}
});
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 を確認できます。
カスタムメイドのソリューションを使用せず、代わりにng-metadata
ライブラリを使用することをお勧めします。 https://github.com/ngParty/ng-metadata で見つけることができます。このように、あなたのコードはAngular 2の可能性と最も互換性があります。
ハッキングなし。オーバーライドなし。生産準備完了。
ここでの回答からカスタムメイドのソリューションを使用した後に切り替えましたが、このライブラリをすぐに使用する方が簡単です。それ以外の場合は、小さな構文変更をすべて移行する必要があります。 1つの例は、ここの他のソリューションが構文を使用することです
@Component('moduleName', 'selectorName', {...})
while 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 からコピー)