AngularJS を使用してHubDB のデータで動的Web ページを構築

CData Connect Server を使用してHubDB OData フィードを作成し、リアルタイムHubDB のデータでシングルページアプリケーションを構築します。

加藤龍彦
デジタルマーケティング

最終更新日:2022-11-13

こんにちは!ウェブ担当の加藤です。マーケ関連のデータ分析や整備もやっています。

AngularJS(Angular)は、動的Web アプリを構造化するフレームワークであり、CData Connect Server と組み合わせることで、HubDB のリアルタイムデータにアクセスできるシングルページアプリケーション(SPA)を構築することができます。 CData Connect Server は、HubDB の仮想データベースを作成し、HubDB のOData API(Angular からネイティブに使用可能)を生成するために使用できます。この記事では、CData Connect Server のセットアップとHubDB のデータへのライブアクセスを持つシンプルなSPA を作成する方法について説明します。

Connect Server を構成する

Angular アプリでリアルタイムHubDB のデータを操作するには、Connect Server からHubDB に接続し、新しい仮想データベースへユーザーアクセスを提供してHubDB のデータのOData エンドポイントを作成する必要があります。

Connect Server ユーザーの追加

AngularJS からConnect Server を介してHubDB に接続するユーザーを作成します。

  1. 「Users」->「 Add」とクリックします。
  2. ユーザーを構成します。 Creating a new user
  3. 「Save Changes」をクリックして新しいユーザーの認証トークンをメモします。 Connect Server users

Connect Server からHubDB に接続

CData Connect Server は、簡単なポイントアンドクリックインターフェースを使用してAPI を生成します。

  1. Connect Server を開き、「Databases」をクリックします。 データベースを追加
  2. 「Available Data Sources」から「HubDB」を選択します。
  3. 必要な認証プロパティを入力し、HubDB に接続します。

    HubDBデータソースへの接続には、パブリックHubSpotアプリケーションを使用したOAuth認証とプライベートアプリケーショントークンを使用した認証の2つの方法があります。

    カスタムOAuthアプリを使用する

    すべてのOAuthフローでAuthSchemeを"OAuth"に設定する必要があります。特定の認証ニーズ(デスクトップアプリケーション、Webアプリケーション、ヘッドレスマシン)に必要な接続プロパティについては、ヘルプドキュメントを確認してください。

    アプリケーションを登録し、OAuthクライアント認証情報を取得するには、以下の手順を実行してください。

    1. HubSpotアプリ開発者アカウントにログインします。
      • アプリ開発者アカウントである必要があります。標準のHubSpotアカウントではパブリックアプリを作成できません。
    2. 開発者アカウントのホームページで、アプリタブをクリックします。
    3. アプリを作成をクリックします。
    4. アプリ情報タブで、ユーザーが接続する際に表示される値を入力し、必要に応じて変更します。これらの値には、パブリックアプリケーション名、アプリケーションロゴ、アプリケーションの説明が含まれます。
    5. 認証タブで、「リダイレクトURL」ボックスにコールバックURLを入力します。
      • デスクトップアプリケーションを作成する場合は、http://localhost:33333のようなローカルにアクセス可能なURLに設定します。
      • Webアプリケーションを作成する場合は、ユーザーがアプリケーションを承認した際にリダイレクトされる信頼できるURLに設定します。
    6. アプリを作成をクリックします。HubSpotがアプリケーションとそれに関連する認証情報を生成します。
    7. 認証タブで、クライアントIDクライアントシークレットを確認します。これらは後でドライバーを設定する際に使用します。
    8. スコープの下で、アプリケーションの意図する機能に必要なスコープを選択します。

      テーブルにアクセスするには、最低限以下のスコープが必要です:

      • hubdb
      • oauth
      • crm.objects.owners.read
    9. 変更を保存をクリックします。
    10. 統合に必要な機能にアクセスできる本番ポータルにアプリケーションをインストールします。
      • 「インストールURL(OAuth)」の下で、完全なURLをコピーをクリックして、アプリケーションのインストールURLをコピーします。
      • コピーしたリンクをブラウザで開きます。アプリケーションをインストールする標準アカウントを選択します。
      • アプリを接続をクリックします。結果のタブは閉じて構いません。

    プライベートアプリを使用する

    HubSpotプライベートアプリケーショントークンを使用して接続するには、AuthSchemeプロパティを"PrivateApp"に設定します。

    以下の手順に従ってプライベートアプリケーショントークンを生成できます:

    1. HubDBアカウントで、メインナビゲーションバーの設定アイコン(歯車)をクリックします。
    2. 左サイドバーメニューで、統合 > プライベートアプリに移動します。
    3. プライベートアプリを作成をクリックします。
    4. 基本情報タブで、アプリケーションの詳細(名前、ロゴ、説明)を設定します。
    5. スコープタブで、プライベートアプリケーションがアクセスできるようにしたい各スコープに対して読み取りまたは書き込みを選択します。
    6. テーブルにアクセスするには、最低限hubdbとcrm.objects.owners.readが必要です。
    7. アプリケーションの設定が完了したら、右上のアプリを作成をクリックします。
    8. アプリケーションのアクセストークンに関する情報を確認し、作成を続行をクリックし、その後トークンを表示をクリックします。
    9. コピーをクリックして、プライベートアプリケーショントークンをコピーします。

    接続するには、PrivateAppTokenを取得したプライベートアプリケーショントークンに設定します。

    Configuring a connection (Salesforce is shown).
  4. Test Database」をクリックします。
  5. 「Permission」->「 Add」とクリックし、適切な権限を持つ新しいユーザー(または既存のユーザー)を追加します。(Reveal に必要なのは、SELECT のみです。)

Connect Server にHubDB OData Endpoints を追加する

HubDB に接続したら、目的のテーブルのOData Endpoints を作成します。

  1. 「OData」->「Tables」->「Add Tables」とクリックします。
  2. HubDB のデータベースを選択します。
  3. 使用するテーブルを選択し、「Next」をクリックします。 Selecting a Table (Salesforce is shown)
  4. (オプション)リソースを編集して特定のフィールドなどを選択します。
  5. 設定を保存します。

(オプション)Cross-Origin Resource Sharing (CORS) を構成する

Ajax などのアプリケーションから複数のドメインにアクセスして接続すると、クロスサイトスクリプティングの制限に違反する恐れがあります。その場合には、「OData」->「Settings」でCORS 設定を構成します。

  • Enable cross-origin resource sharing (CORS):ON
  • Allow all domains without '*':ON
  • Access-Control-Allow-Methods:GET、PUT、POST、OPTIONS
  • Access-Control-Allow-Headers:Authorization

設定への変更を保存します。

Configuring CORS settings

OData フィードのサンプルURL

HubDB への接続を構成してユーザーを作成し、Connect Server でOData エンドポイントを作成すると、HubDB のデータのOData フィードにアクセスできるようになります。 以下は、テーブルにアクセスするためのURL とテーブルのリストです。テーブルへのアクセスについては、Connect Server のAPI ページを参照してください。(Connect Server web ページの右上にある「API」リンクをクリックします。) URL については、Connect Server のURL が必要になります。(例:CONNECT_SERVER_URL/) Angular を使用しているため、デフォルトでJSON データを返さないURL の末尾には@json パラメータを追加します。

テーブル         URL
エンティティ(テーブル)のリスト CONNECT_SERVER_URL/api.rsc/
NorthwindProducts テーブルのメタデータ http://www.cdatacloud.net/myinstance/api.rsc/NorthwindProducts/$metadata?@json
NorthwindProducts http://www.cdatacloud.net/myinstance/api.rsc/HubDB_NorthwindProducts

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

シングルページアプリケーションを構築する

Connect Server のセットアップが完了したら、SPA を構築することができるようになります。本記事は簡単なデモンストレーションなので、すべてのCSS、スクリプト、およびAngular コントローラーを一つのファイルにまとめることで、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.7.8/angular.min.js"></script>

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

次に、HTML の本文でのみAngular を使用するため、このbody タグにng-app およびng-controller ディレクティブを追加します。 そして、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 関数を呼び出すことです。 ほかのすべての関数は必要に応じて呼び出され、これらの関数呼び出しでは、HubDB のデータを取得するためにConnect 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
 * Connect Server.
 */
function init() {
  $scope.data = {
  availableTables: [],
                 availableColumns: [],
                 selectedTable: {},
                 tableData: []
  };

  /*
   * Call to Connect Server to get the list of Tables, select the
   * first table by default, and retrieve the available columns.
   *
   * The call to Connect Server returns standard OData, so the
   * data we need is in the value object in the JSON returned.
   */
  $http.get("http://www.cdatacloud.net/myinstance/api.rsc",{headers: {"x-cdata-authtoken":"MyAuthtoken"}})
    .then(function (response) {
        $scope.data.availableTables = response.data.value;
        $scope.data.selectedTable = $scope.data.availableTables[0];
        $scope.getTableColumns();
        });
}

/*
 * Call to Connect 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://www.cdatacloud.net/myinstance/api.rsc/" + table + "/$metadata?@json", {headers: {"x-cdata-authtoken":"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 Connect 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 Connect 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://www.cdatacloud.net/myinstance/api.rsc/" + table + "?$select=" + columnString, {headers: {"x-cdata-authtoken":"MyAuthtoken"}})
      .then(function (response) { $scope.data.tableData = response.data.value; });
  } else {
    $scope.data.tableData = [];
  }
}

Web ページを作成する

コントローラーを定義したら、Angular を使用してWeb ページが作成できるようになります。この例のページは、テーブルを選択するためのセレクトボックス、カラムを選択するための(マルチ)セレクトボックス、データを取得するためのボタン、そしてデータを表示するためのテーブルという4 つの主要部分で構成されます。 これらの4 つの部分を一つずつ取り上げて、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 要素を入力する前にカラムを名前でソートします。 このselect にはmultiple 属性が含まれるため、複数のカラムを選択できます。 選択したカラムは、それぞれ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 ディレクティブを使用します。まず、選択したカラムを繰り返し処理してテーブルヘッダーを作成するディレクティブ、次に、返されたデータ行を繰り返し処理するディレクティブ、そして、選択したカラムを繰り返し処理して指定したデータ行に対応するデータを表示するディレクティブです。

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.7.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>
<br />
<br />
<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>
<br />
<br />
<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
     * Connect Server.
     */
    function init() {
    $scope.data = {
    availableTables: [],
    availableColumns: [],
    selectedTable: {},
    tableData: []
};

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

/*
 * Call to Connect 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("CONNECT_SERVER_URL/api.rsc/" + table + "/$metadata?@json", {headers: {"x-cdata-authtoken":"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 Connect 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 Connect 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("CONNECT_SERVER_URL/api.rsc/" + table + "?$select=" + columnString, {headers: {"x-cdata-authtoken":"MyAuthtoken"}})
      .then(function (response) { $scope.data.tableData = response.data.value; });
  } else {
    $scope.data.tableData = [];
  }
}
});
</script>
</body>
</html>

無料トライアルと詳細

Angularで構築されたWeb アプリケーションからHubDB のデータ(またはサポートされているほかのデータソースからのデータ)に接続したい場合には、CData Connect Server の無料トライアルに今すぐ登録してください。 Connect Server の詳細と、サポートされているほかのデータソースについては、Connect Server ページを参照してください。

トライアル・お問い合わせ

30日間無償トライアルで、CData のリアルタイムデータ連携をフルにお試しいただけます。記事や製品についてのご質問があればお気軽にお問い合わせください。