AngularJS を使用し、Linear のデータで動的なWeb ページを構築

古川えりか
古川えりか
コンテンツスペシャリスト
Linear に接続できるシングルページアプリケーションを作成します。



AngularJS (Angular) は、動的なWeb アプリケーションを構築するための構造化フレームワークです。Angular と CData API Server、およびLinear コネクタ(または数百種類のデータソースコネクタ)を使用すると、Linear へのリアルタイムアクセスを備えたシングルページアプリケーション(SPA)を構築できます。 この記事では、CData API Server を設定し、Linear へのライブアクセスを備えたシンプルなSPA を作成する手順を説明します。SPA はHTML テーブルを動的に作成・表示します。

API Server の設定

以下のリンクからAPI Server の無償トライアルをスタートしたら、セキュアなLinear OData サービスを作成していきましょう。

Linear への接続

Angular からLinear のデータを操作するには、まずLinear への接続を作成・設定します。

  1. API Server にログインして、「Connections」をクリック、さらに「接続を追加」をクリックします。 接続を追加
  2. 「接続を追加」をクリックして、データソースがAPI Server に事前にインストールされている場合は、一覧から「Linear」を選択します。
  3. 事前にインストールされていない場合は、コネクタを追加していきます。コネクタ追加の手順は以下の記事にまとめてありますので、ご確認ください。
    CData コネクタの追加方法はこちら >>
  4. それでは、Linear への接続設定を行っていきましょう! 接続設定
  5. Linear への認証には、個人用 API キーまたは OAuth 2.0 を使用できます。ご自身の Linear アカウントで接続する場合は、API キーを使うのが最も手軽です。

    API キーによる認証

    以下の接続プロパティを設定します。

    • AuthScheme:APIKey に設定します。
    • APIKey:Linear の個人用 API キー。

    個人用 API キーを作成するには、Linear にログインして Settings > Security & access > Personal API keys を開き、New API key を選択して作成します。キーは一度しか表示されないため、すぐにコピーしておきましょう。

    OAuth による認証

    OAuth を使用するには、Linear にカスタム OAuth アプリケーションを登録する必要があります(Settings > API > OAuth applications)。登録すると OAuthClientId と OAuthClientSecret が発行されます。対応しているフローは以下の 2 つです。

    • Authorization code:AuthScheme を OAuth、InitiateOAuth を GETANDREFRESH に設定し、OAuthClientId、OAuthClientSecret、およびアプリケーションで定義した CallbackURL(例:http://localhost:33333)を指定します。ドライバーがブラウザで Linear を開くので、アクセスを許可してください。
    • Client credentials:AuthScheme を OAuthClient に設定し、OAuthClientId と OAuthClientSecret を指定します。アプリケーション自体を認証するためブラウザ操作は不要で、マシン間(M2M)連携に適しています。

    デフォルトでは、ドライバーは read,write スコープをリクエストします。アクセストークンは有効期限が切れると自動で更新されます。

  6. 接続情報の入力が完了したら、「保存およびテスト」をクリックします。

Linear への認証には、個人用 API キーまたは OAuth 2.0 を使用できます。ご自身の Linear アカウントで接続する場合は、API キーを使うのが最も手軽です。

API キーによる認証

以下の接続プロパティを設定します。

  • AuthScheme:APIKey に設定します。
  • APIKey:Linear の個人用 API キー。

個人用 API キーを作成するには、Linear にログインして Settings > Security & access > Personal API keys を開き、New API key を選択して作成します。キーは一度しか表示されないため、すぐにコピーしておきましょう。

OAuth による認証

OAuth を使用するには、Linear にカスタム OAuth アプリケーションを登録する必要があります(Settings > API > OAuth applications)。登録すると OAuthClientId と OAuthClientSecret が発行されます。対応しているフローは以下の 2 つです。

  • Authorization code:AuthScheme を OAuth、InitiateOAuth を GETANDREFRESH に設定し、OAuthClientId、OAuthClientSecret、およびアプリケーションで定義した CallbackURL(例:http://localhost:33333)を指定します。ドライバーがブラウザで Linear を開くので、アクセスを許可してください。
  • Client credentials:AuthScheme を OAuthClient に設定し、OAuthClientId と OAuthClientSecret を指定します。アプリケーション自体を認証するためブラウザ操作は不要で、マシン間(M2M)連携に適しています。

デフォルトでは、ドライバーは read,write スコープをリクエストします。アクセストークンは有効期限が切れると自動で更新されます。

API Server のユーザー設定

次に、API Server 経由でLinear にアクセスするユーザーを作成します。「Users」ページでユーザーを追加・設定できます。やってみましょう。

  1. 「Users」ページで ユーザーを追加をクリックすると、「ユーザーを追加」ポップアップが開きます。
  2. 次に、「ロール」、「ユーザー名」、「権限」プロパティを設定し、「ユーザーを追加」をクリックします。 新しいユーザーの構成
  3. その後、ユーザーの認証トークンが生成されます。各ユーザーの認証トークンとその他の情報は「Users」ページで確認できます。 API Server のユーザー設定

Linear 用のAPI エンドポイントの作成

ユーザーを作成したら、Linear のデータ用のAPI エンドポイントを作成していきます。

  1. まず、「API」ページに移動し、 「 テーブルを追加」をクリックします。 テーブルを追加
  2. アクセスしたい接続を選択し、次へをクリックします。 接続の選択
  3. 接続を選択した状態で、各テーブルを選択して確認をクリックすることでエンドポイントを作成します。 接続からのテーブルの追加

OData のエンドポイントを取得

以上でLinear への接続を設定してユーザーを作成し、API Server でLinear データのAPI を追加しました。これで、OData 形式のLinear データをREST API で利用できます。API Server の「API」ページから、API のエンドポイントを表示およびコピーできます。

API エンドポイント

CORS を有効にする

AngularJS では、サーバーでCORS (Cross-origin resource sharing) を有効にする必要があります。API Server の[SETTINGS Server]タブに移動すると、CORS を有効にできます。 以下の設定を調整する必要があります。

  • チェックボックスをクリックして「Enable cross-origin resource sharing (CORS)]をクリックします。
  • チェックボックスをクリックして[Allow all domains without '*']を選択するか、Access-Control-Allow-Origin で接続を許可するドメインを指定します。
  • Access-Control-Allow-Methods を[GET,PUT,POST,OPTIONS]に設定します。
  • Access-Control-Allow-Headers を[authorization]に設定します。
  • [Save Changes]をクリックします。

OData フィードのサンプルURL

Linear への接続を構成し、ユーザーを作成してAPI Server にテーブルを追加すれば、それらのテーブルのOData フィードにアクセスできます。 以下は、テーブルにアクセスするためのURL とテーブルのリストです。テーブルへのアクセスについては、([API Server Web]ページの右上にあるAPI リンクをクリックして)API Server のAPI ページに移動できます。 URL には、API Server のアドレスとポートが必要です。 Angular を使用しているため、デフォルトではJSON データを返さないURL の末尾に@json パラメータを追加します。

Table         URL
Entity (table) List http://address:port/api.rsc/
Metadata for table Team http://address:port/api.rsc/Team/$metadata?@json
Account http://address:port/api.rsc/Team

返されるフィールドを制限する場合には、標準のOData フィードと同様に、$select パラメータを$filter、$orderby、$skip、$top などの他の標準のOData URL パラメータとともにクエリに追加できます。 サポートされているOData クエリの詳細については、ヘルプドキュメントを参照してください。

シングルページアプリケーションの構築

API Server のセットアップが完了したら、SPA を構築する準備が整います。これは単純なデモンストレーションなので、すべてのCSS、スクリプト、およびAngular コントローラーを1 つのファイルに含め、AngularJS サービス、ファクトリ、およびカスタムディレクティブによって提供される機能を意図的に使用しないようにします。

CSS 定義とAngularJS ライブラリのインポート

まずCSS ルールセットをいくつか作成し、table、th、td、tr 要素を変更してデータのテーブルをフォーマットします。また、SPA で使用するためにAngularJS ライブラリをインポートする必要があります。


  <style>
  table, th, td {
    border:1px solid grey;
    border-collapse: collapse;
    padding:5px;
  }
  table tr:nth-child(odd) {
    background-color: #f1f1f1;
  }
  table tr:nth-child(even) {
    background-color: #ffffff;
  }
  </style>
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>

Angular アプリとコントローラーオブジェクトの作成と参照

次に、HTML の[body]タグにng-app ディレクティブとng-controller ディレクティブを追加します。これは、本体がAngular を使用す唯一の場所であるために必要な操作です。 そして、HTML 本文の最後にAngular アプリとコントローラーを作成及び定義するスクリプトタグを作成します。


<body ng-app="DataApp" ng-controller="SimpleController">
...
<script>
var app = angular.module('DataApp', []);
app.controller('SimpleController', function($scope, $http) {
    //we will add code here
    });
</script>
</body>

コントローラーの定義

ここでのコントローラーはAngular オブジェクトを初期化してSPA を設定するinit、選択したテーブルのカラムを取得するgetTableColumns、選択したカラムから選択したフィールドのデータを取得するgetTableData の3つの関数で構成されます。 コントローラを作成するときの最初のアクションとして、init 関数を呼び出します。 他のすべての関数は必要に応じて呼び出され、これらの関数呼び出しでLinear のデータを取得するために、API Server に対して必要なHTTP GET 呼び出しを行います。


init();

/*
 * Initialize the data object, which will be used with Angular to
 * build the different parts of our SPA and to retrieve data from
 * the API Server.
 */
function init() {
  $scope.data = {
  availableTables: [],
                 availableColumns: [],
                 selectedTable: {},
                 tableData: []
  };

  /*
   * Call to the API Server to get the list of Tables, select the
   * first table by default, and retrieve the available columns.
   *
   * The call to the API Server returns standard OData, so the
   * data we need is in the value object in the JSON returned.
   */
  $http.get("http://server:port/api.rsc",{headers: {"Authorization":"Basic "  + btoa("MyUser:MyAuthtoken")}})
    .then(function (response) {
        $scope.data.availableTables = response.data.value;
        $scope.data.selectedTable = $scope.data.availableTables[0];
        $scope.getTableColumns();
        });
}

/*
 * Call to the API Server to get the list of columns for the
 * selected table.
 *
 * The data returned here is not standard OData, so we drill
 * down into the response to extract exactly the data we need
 * (an array of column names).
 *
 * With the column names retrieved, we will transform the array
 * of column names into an array of objects with a name and Id
 * field, to be used when we build an HTML select.
 */
$scope.getTableColumns = function () {
  $scope.data.tableData = [];
  $scope.data.selectedColumns = [];
  table = $scope.data.selectedTable.url;
  if (table != "") {
    $http.get("http://server:port/api.rsc/" + table + "/$metadata?@json", {headers: {"Authorization":"Basic "  + btoa("MyUser:MyAuthtoken")}})
      .then(function (response) {
          $scope.data.availableColumns = response.data.items[0]["odata:cname"];
          for (i = 0; i < $scope.data.availableColumns.length; i++) {
            $scope.data.availableColumns[i] = { id: i, name: $scope.data.availableColumns[i] };
          }
          });
  }
}

/*
 * Call to the API Server to get the requested data.We get the data
 * based on the table selected in the associated HTML select.
 * Then we create a comma-separated string of the selected columns.
 *
 * With the table and columns known, we can make the appropriate call
 * to the API Server.Because the driver returns standard OData, the
 * table data is found in the value field of the response.
 */
$scope.getTableData = function () {
  table = $scope.data.selectedTable.url;
  columnsArray = $scope.data.selectedColumns;
  columnString = "";
  for (i = 0; i < columnsArray.length; i++) {
    if (columnString != "") {
      columnString += ",";
    }
    columnString += columnsArray[i].name;
  }

  if (table != "") {
    $http.get("http://server:port/api.rsc/" + table + "?$select=" + columnString, {headers: {"Authorization":"Basic "  + btoa("MyUser:MyAuthtoken")}})
      .then(function (response) { $scope.data.tableData = response.data.value; });
  } else {
    $scope.data.tableData = [];
  }
}

Web ページの構成

コントローラを定義したら、Angular を使用してWeb ページを構築する準備が整います。単純なページには、テーブルを選択するための選択ボックス、カラムを選択するための選択(複数)ボックス、データを取得するためのボタン、およびデータを表示するためのテーブルの4つの主要部分があります。 これら4つの部分の1つずつを通して、Angular の使用方法について説明します。

テーブルを選択

最初のselect 要素では、ng-options ディレクティブを使用し、使用可能なテーブル(前述のinit 関数から取得) を反復処理し、select 要素にデータを入力します。 ng-model ディレクティブを使用して、選択したオプションの値をdata.selectedTable フィールドに割り当てます。 選択したテーブルが変更された場合は、getTableColumns 関数を呼び出して使用可能なカラムを再設定します。


  <label>Select a Table</label>
  <br />
  <select name="tableDropDown" id="tableDropDown"
          ng-options="table.name for table in data.availableTables track by table.url"
          ng-model="data.selectedTable"
          ng-change="getTableColumns()">
  </select>

カラムを選択

2番目のselect 要素では、再びng-options ディレクティブを使用しますが、今回は、(getTableColumns 関数によって取得された)使用可能なカラムを反復処理します。 使いやすさのために、select 要素に入力する前にカラムを名前でソートします。 この選択には複数 の属性が含まれているため、複数のカラムを選択できます。 選択した各列がdata.selectedColumns 配列に追加されます。カラムを選択すると、各列のテーブルヘッダーが作成されます(以下のデータテーブルのセクションを参照)。


  <label>Select Columns</label>
  <br />
  <select name="columnMultiple" id="columnMultiple"
          ng-options="column.name for column in data.availableColumns | orderBy:'name' track by column.id"
          ng-model="data.selectedColumns"
          multiple>
  </select>

テーブルデータを取得

このボタンでは、ボタンがクリックされるたびにgetTableData 関数を呼び出します。ユーザーがカラムを選択していない場合に、ng-disabled ディレクティブを使用してボタンを無効にしていることに注意してください。 また、選択したテーブルの名前でボタンのテキストを動的に更新します。


  <button name="getTableData" id="btnGetTableData"
          ng-click="getTableData()"
          ng-disabled="data.selectedColumns.length == 0">
  Get {{data.selectedTable.name}} Data
  </button>

テーブルデータを表示

このセクションは、選択したテーブルのデータを表示するというSPA の最終目標を満たしています。そのために、いくつかのng-repeat ディレクティブを使用します。1つは選択したカラムを反復処理してテーブルヘッダーを作成し、もう一つは返されたデータの行を反復処理して対応するデータを特定の行に表示します。

Angular を使用することで、表示するカラムを動的に決定できます。データがクリックされる「前」に選択されたカラムのみにデータが含まれることに注意してください。 使用可能なすべてのカラムを選択し、ボタンをクリックしてテーブルデータを取得してから、戻って別のカラムを選択または選択解除し、表示されるデータを変更することは簡単にできます。 選択したテーブルを変更すると、すべてのデータがクリアされます。


  <table>
    <tr>
      <th ng-repeat="column in data.selectedColumns | orderBy:'name'">{{column.name}}</th>
    </tr>
    <tr ng-repeat="row in data.tableData">
      <td ng-repeat="column in data.selectedColumns">{{ row[column.name] }}</td>
    </tr>
  </table>

アプリの完成

<!DOCTYPE html>

<html>
<style>
table, th, td {
border:1px solid grey;
        border-collapse: collapse;
padding:5px;
}
table tr:nth-child(odd) {
  background-color: #f1f1f1;
}
table tr:nth-child(even) {
  background-color: #ffffff;
}
</style>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body ng-app="DataApp" ng-controller="SimpleController">
<label>Select a Table</label>
<br>
<select name="tableDropDown" id="tableDropDown"
ng-options="table.name for table in data.availableTables track by table.url"
ng-model="data.selectedTable"
ng-change="getTableColumns()">
</select>
<label>Select Columns</label>
<br />
<select name="columnMultiple" id="columnMultiple"
ng-options="column.name for column in data.availableColumns | orderBy:'name' track by column.id"
ng-model="data.selectedColumns"
multiple>
</select>
<button name="getTableData" id="btnGetTableData"
ng-click="getTableData()"
ng-disabled="data.selectedColumns.length == 0">
Get {{data.selectedTable.name}} Data
</button>
<br />
<br />

<table>
<tr>
<th ng-repeat="column in data.selectedColumns | orderBy:'name'">{{column.name}}</th>
</tr>
<tr ng-repeat="row in data.tableData">
<td ng-repeat="column in data.selectedColumns">{{ row[column.name] }}</td>
</tr>
</table>
<script>
var app = angular.module('DataApp', []);
app.controller('SimpleController', function($scope, $http) {
    init();

    /*
     * Initialize the data object, which will be used with Angular to
     * build the different parts of our SPA and to retrieve data from
     * the API Server.
     */
    function init() {
    $scope.data = {
    availableTables: [],
    availableColumns: [],
    selectedTable: {},
    tableData: []
};

/*
 * Call to the API Server to get the list of tables, select the
 * first table by default, and retrieve the available columns.
 *
 * The call to the API Server returns standard OData, so the
 * data we need is in the value object in the JSON returned.
 */
$http.get("http://server:port/api.rsc",{headers: {"Authorization":"Basic "  + btoa("MyUser:MyAuthtoken")}})
.then(function (response) {
    $scope.data.availableTables = response.data.value;
    $scope.data.selectedTable = $scope.data.availableTables[0];
    $scope.getTableColumns();
    });
}

/*
 * Call to the API Server to get the list of columns for the
 * selected table.
 *
 * The data returned here is not standard OData, so we drill
 * down into the response to extract exactly the data we need
 * (an array of column names).
 *
 * With the column names retrieved, we will transform the array
 * of column names into an array of objects with a name and Id
 * field, to be used when we build an HTML select.
 */
$scope.getTableColumns = function () {
  $scope.data.tableData = [];
  $scope.data.selectedColumns = [];
  table = $scope.data.selectedTable.url;
  if (table != "") {
    $http.get("http://server:port/api.rsc/" + table + "/$metadata?@json", {headers: {"Authorization":"Basic "  + btoa("MyUser:MyAuthtoken")}})
      .then(function (response) {
          $scope.data.availableColumns = response.data.items[0]["odata:cname"];
          for (i = 0; i < $scope.data.availableColumns.length; i++) {
          $scope.data.availableColumns[i] = { id: i, name: $scope.data.availableColumns[i] };
          }
          });
  }
}

/*
 * Call to the API Server to get the requested data.We get the data
 * based on the table selected in the associated HTML select.
 * Then we create a comma-separated string of the selected columns.
 *
 * With the table and columns known, we can make the appropriate call
 * to the API Server.Because the driver returns standard OData, the
 * table data is found in the value field of the response.
 */
$scope.getTableData = function () {
  table = $scope.data.selectedTable.url;
  columnsArray = $scope.data.selectedColumns;
  columnString = "";
  for (i = 0; i < columnsArray.length; i++) {
    if (columnString != "") {
      columnString += ",";
    }
    columnString += columnsArray[i].name;
  }

  if (table != "") {
    $http.get("http://server:port/api.rsc/" + table + "?$select=" + columnString, {headers: {"Authorization":"Basic "  + btoa("MyUser:MyAuthtoken")}})
      .then(function (response) { $scope.data.tableData = response.data.value; });
  } else {
    $scope.data.tableData = [];
  }
}
});
</script>
</body>
</html>

無料トライアルと詳細

Angular で構築されたWeb アプリケーションからLinear (またはサポートされている他のデータソースからのデータ)に接続したい場合は、今すぐAPI Server の30日間無料トライアルダウンロードしてください。 API のより一般的な情報およびサポートされている他のデータソースについてはAPI Server ページを参照してください。

はじめる準備はできましたか?

詳細はこちら、または無料トライアルにお申し込みください:

CData API Server