Help us understand the problem. What is going on with this article?

AngularJSのcomponentをTypeScriptで実装してみる

More than 3 years have passed since last update.

はじめに

 AngularJSの1.5.xより component が実装され、巷の噂ではAngularJSはTypeScriptを相性が良いとのことで、実装方法を研究したメモを残す。

開発環境

  • VisualStudio 2015
  • プロジェクトのプロパティの「TypeScriptビルド」の「出力」項目、「Javascript 出力をファイルに統合する」にチェックを入れ、値を「application.js」にする
  • NuGetで、以下のパッケージを読み込む
    1. es6-promise.TypeScript.DefinitelyTyped (v0.1.3)
    2. angularjs.TypeScript.DefinitelyTyped (v5.4.2)
    3. jquery.TypeScript.DefinitelyTyped (v3.0.4)

Viewの実装

単純にcomponentで作成されたタグを表示する

index.html
<!DOCTYPE html>
<html lang="ja" ng-app="app">
<head>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="app.css" type="text/css" />
    <script src="https://code.jquery.com/jquery-2.2.1.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script>

    <script src="application.js"></script>
</head>
<body ng-controller="MainController as main">
    <h1 ng-bind="main.title"></h1>
    <element-test param-title="main.subTitle" call-back-event="main.callback1(value)"></element-test>
</body>
</html>

element-testの仕様

  1. param-title : element-testの中で表示するタイトル
  2. call-back-event : コントローラ側のイベントを呼び出す

モジュール定義

angularのappを定義します

app.ts
/// <reference path="_include.ts" />
module app {
    var module = angular.module('app', []);
    module.controller('MainController', MainController);
    module.component('elementTest', ElementComponentFactory());
}
_include.ts
/// <reference path="scripts/typings/jquery/jquery.d.ts" />
/// <reference path="scripts/typings/angularjs/angular.d.ts" />
/// <reference path="scripts/typings/es6-promise/es6-promise.d.ts" />

/// <reference path="main.controller.ts" />
/// <reference path="element.component.ts" />

メインコントローラ

main.controller.ts
/// <reference path="_include.ts" />
module app {
    /**
     * メイン コントローラ
     */
    export class MainController {
        // タイトル
        title: string;
        // サブタイトル
        subTitle: string;
        // コールバック
        callback1: Function;
        /**
         * コンストラクタ
         */
        constructor() {
            this.title = "AngularJS(1.5)でcomponent実装";

            this.subTitle = "コントローラから設定したパラメタ";

            // コールバックの設定
            this.callback1 = (value : any) => {
                // コールバックが呼び出される。valueは「1001」
            }
        }
    }
}

コンポーネント

element.component.ts
/// <reference path="_include.ts" />
module app {
    /**
     * Element コンポーネント作成
     */
    export function ElementComponentFactory(): ng.IComponentOptions {
        return {
            bindings:
            {
                //コントローラパラメタ
                paramTitle: '=',
                //コールバック
                callBackEvent: '&'
            },

            template: [
                    "<div>",
                    "<p ng-bind='_my.displayItem'></p>",
                    "<button ng-click='_my.clickButton(123)'>ボタン</button>",
                    "</div>"
                ].join(""),
            controllerAs: '_my',
            controller: ElementComponent
        };
    }
    /**
     * コントローラ
     * @returns
     */
    class ElementComponent {
        public static $inject = ['$http'];  // httpサービスの注入

        /**
         * 表示項目
         */
        displayItem: string;
        /**
         * コールバック
         */
        callBackEvent: Function;

        // タイトル
        private _paramTitle: string;  
        get paramTitle (): string {
            return this._paramTitle;
        }
        /**
         * コントローラとのI/O
         * @param {string} value
         */
        set paramTitle(value: string) {
            if (!angular.isDefined(value)) {
                return;
            }
            this._paramTitle = value;
            // パラメタが設定された処理
            this.displayItem = value;
        } 
        /**
         * コンストラクタ
         * @param {ng.IHttpService} public $http
         */
        constructor(public $http: ng.IHttpService) {
            // this.$http で httpサービスが使用可能
        }
        /**
         * ボタンが押された
         * @param {number} value 値
         */
        clickButton(value: number): void {
            // valueは「123」が設定されている
            this.callBackEvent({ 'value': 1001 });
            this.paramTitle = "ボタン押下";
        }
    }
}

ポイント

  • component の controller は class で実装する
  • 従来 $scope 経由で操作していたプロパティ類は、controller class のプロパティで宣言する
  • コントローラからの値受信は、 setter の中で処理を行う
  • コントローラへの callback は Function型 で定義したプロパティを呼び出す

最後に

自分は、Javascriptと言う言語が気持ち悪くて、コード実装時はモチベーションが事が下がったままでしたが、TypeScriptの場合は綺麗なコードになり、書いてて楽しくなりました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした