Angular と Connect Server を使用した関連テーブルのデータ表示



Angular は、Angular JS の原則に基づいて構築・拡張された、動的な Web アプリ向けの最新フレームワークです。CData Connect Server を使用すると、250 以上のデータソース(オンプレミスおよびクラウドベースのデータベースを含む)に対して REST API を生成できます。この記事では、CData Connect Server をセットアップして QuickBooks Online データ用の OData ベース REST API を作成し、QuickBooks Online データにライブアクセスできるシンプルなシングルページアプリケーション(SPA)を構築する手順を解説します。この SPA は、関連する QuickBooks Online テーブル(Invoices と Invoice Line Items など)に基づいて、HTML テーブルを動的に構築・表示します。この記事では主要なコードを順を追って説明しますが、サンプル Angular プロジェクトをダウンロードして、完全なソースコードの確認や機能のテストを行うこともできます。

Connect Server のセットアップ

まだインストールしていない場合は、CData Connect Server をダウンロードしてください。Connect Server をインストールしたら、アプリケーションを起動し、データへの接続を設定します(この記事では付属のサンプルデータベースを使用します)。次に、SPA でアクセスしたいテーブル用の REST API を作成するようにアプリケーションを設定します。

CORS の有効化

Angular Web アプリと Connect Server が異なるドメインにある場合、Angular アプリはクロスドメインリクエストを生成します。そのため、Angular Web アプリからクエリされるサーバーでは CORS(クロスオリジンリソース共有)を有効にする必要があります。Connect Server で CORS を有効にするには、Connect Server の SETTINGS ページにある Server タブに移動し、以下の設定を調整します。

  • 「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 をクリックします。

QuickBooks Online への接続

デプロイ後、Connect Server 管理コンソールで Settings -> Connections をクリックし、新しい接続を追加して、QuickBooks Online への接続に必要な認証値やその他の接続プロパティを指定します。

QuickBooks Online は OAuth 認証標準を使用します。OAuth では、認証ユーザーがブラウザを通じてログインする必要があります。OAuth を使用して認証するには、組み込みの OAuthClientId、OAuthClientSecret、CallbackURL を使用するか、Intuit でアプリを登録して独自の値を取得します。また、CompanyId も指定する必要があります。

OAuth の使用方法については、ヘルプドキュメントの「はじめに」の章を参照してください。

ユーザーの設定

次に、Connect Server を通じてデータベースデータにアクセスするためのユーザーを作成します。USERS タブでユーザーを追加・設定できます。ここではデータ閲覧用のシンプルな SPA を作成するため、読み取り専用アクセス権を持つユーザーを作成します。 Add をクリックし、ユーザー名を入力して Save Changes をクリックします。

スクリーンショットに示されているように、読み取りおよび書き込みアクセス権を持つユーザーが既に設定されています。この記事では、読み取り専用ユーザーと、その関連する authtoken を使用して Connect Server にアクセスします。

テーブルへのアクセス

ユーザーを作成したら、データベーステーブルへのアクセスを有効にします。テーブルを有効にするには、ODATA タブに移動して Add Tables をクリックします。アクセスしたいデータ接続を選択し、 Next をクリックします。接続を選択した状態で、テーブル名をクリックして Next を選択することでリソースの有効化を開始できます。リソースは一度に1つのテーブルずつ追加する必要があります。この例では、すべてのテーブルを有効にしています。

REST API のサンプル URL

データベースへの接続を設定し、ユーザーを作成し、Connect Server にリソースを追加したことで、OData プロトコルに基づいた簡単にアクセスできる REST API が完成しました。以下に、テーブルとそれらにアクセスするための URL のリストを示します。テーブルへのアクセス方法については、ODATA ページにある API タブを参照してください。URL には Connect Server の addressport が必要です。Angular を使用しているため、デフォルトで JSON データを返さない URL には @json パラメータを末尾に追加します。

テーブル URL
エンティティ(テーブル)リスト http://address:port/api.rsc/
QBO_Invoices テーブルのメタデータ http://address:port/api.rsc/QuickBooksOnlineConnection_Accounts/$metadata?@json
QBO_Invoices データ http://address:port/api.rsc/QuickBooksOnlineConnection_Accounts

標準の OData フィードと同様に、返されるフィールドを制限したい場合は、クエリに $select パラメータを追加できます。また、$filter$orderby$skip$top などの標準 URL パラメータも使用できます。

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

Connect Server のセットアップが完了したら、SPA を構築していきましょう。.zip ファイルに含まれる SPA のソースファイルを順を追って説明し、重要なコードセクションについて解説します。いくつかのソースファイルは、angular.io の Angular チュートリアルをベースにしています。

src/index.html


これは SPA のホームページで、ソースコードは主に必要な Angular ライブラリをインポートするための script 要素で構成されています。

src/main.ts


この TypeScript ファイルはアプリをブートストラップします。

src/app/app.module.ts


この TypeScript ファイルは、SPA を作成・実行するために必要なモジュールをインポートするクラスを作成します。このクラスには、コンポーネントとサービスの定義が含まれています。

src/app/app-routing.module.ts


この TypeScript ファイルは、SPA のコンテンツ間を移動するためのルートとパスを定義します。

src/app/app.component.css


このファイルは、Web アプリ内の h1 要素と h2 要素を変更する CSS ルールセットを作成します。

src/app/app.component.ts


この TypeScript ファイルは、SPA 用のコンポーネントを作成し、テンプレートを定義します。このアプリはシンプルですが、複数のルーティングやコンポーネントを含むように容易に拡張できます。

src/app/dashboard.component.css


このファイルは、HTML 内の tablethtd 要素を変更する CSS ルールセットを作成します。

src/app/dashboard.component.html


このファイルは、SPA のダッシュボードコンポーネントのレイアウトを定義します。テンプレートには、テーブルと関連テーブルを選択するドロップダウン、テーブルの外部キーを示すカラムを選択するドロップダウン、親テーブルデータを表示する HTML テーブル、子テーブルデータを表示する別の HTML テーブルが含まれています。*ngIf ディレクティブの条件に基づいてセクションの表示/非表示が切り替わり、*ngFor ディレクティブを使用して Connect Server への呼び出し結果をループ処理することで、メニューとテーブルが動的に構築されます。

Connect Server へのすべての呼び出しと変数への値の割り当ては、DashboardComponent クラスと AppService クラスで行われます。

<div style='float:left' class="table_select">
            <label>Select a Table</label>
            <br>
            <select [(ngModel)]="selectedTable" (change)="tableChanged()">
                <option *ngFor="let sel_table of tableNames" [value]="sel_table">{{sel_table}}</option>
            </select>
            <br>
            <div *ngIf="selectedTable">
                <label>Select the Key for [{{selectedTable}}]</label>
                <br>
                <select [(ngModel)]="tableKey">
                    <option *ngFor="let sel_column of tableColumns" [value]="sel_column">{{sel_column}}</option>
                </select>
                <br>
            </div>
        </div>
        <div class="subtable_select" *ngIf="selectedTable">
            <label>Select a SubTable</label>
            <br>
            <select [(ngModel)]="selectedSubTable" (change)="subTableChanged()">
                <option *ngFor="let sel_table of tableNames" [value]="sel_table">{{sel_table}}</option>
            </select>
            <br>
            <div *ngIf="selectedSubTable">
                <label>Select the Key for [{{selectedSubTable}}]</label>
                <br>
                <select *ngIf="selectedSubTable" [(ngModel)]="subTableKey">
                    <option *ngFor="let sel_column of subTableColumns" [value]="sel_column">{{sel_column}}</option>
                </select>
                <br>
            </div>
        </div>
        <div *ngIf="selectedTable && tableKey && selectedSubTable && subTableKey && tableData?.length > 0" class="data_retrieve">
            <br>
            <h2>Click an Entry from [{{selectedTable}}] to Expand the [{{selectedSubTable}}] Entities</h2>
            <table>
                <tr>
                    <th *ngFor="let column of tableColumns">{{ column }}</th>
                </tr>
                <tr style='cursor:pointer' *ngFor="let row of tableData" (click)="rowClicked(row[tableKey])">
                    <td *ngFor="let column of tableColumns">{{ row[column] }}</td>
                </tr>
            </table>
        </div>
        <div *ngIf="selectedSubTable && subTableColumns && subTableData?.length > 0">
            <br>
            <hr>
            <h2>Data from [{{selectedSubTable}}]</h2>
            <table>
                <tr>
                    <th *ngFor="let column of subTableColumns">{{ column }}</th>
                </tr>
                <tr *ngFor="let row of subTableData">
                    <td align=center *ngFor="let column of subTableColumns">{{ row[column] }}</td>
                </tr>
            </table>
        </div>

src/app/app.service.ts


この TypeScript ファイルは、Connect Server からデータを取得するためのサービスを構築します。テーブルリストの取得、特定のテーブルのカラムリストの取得、テーブルからのデータ取得といった関数が含まれています。また、Connect Server が返すテーブルのメタデータを表すクラスも定義されています。

API_Table

Connect Server がテーブルに対して返すメタデータには、テーブルの name、kind、URL が含まれます。ここでは name フィールドのみを使用しますが、SPA を拡張する際に他の情報が必要になる場合に備えて、オブジェクト全体を渡しています。

export class API_Table {
        name: string;
        kind: string;
        url: string;
        }

constructor()

コンストラクターでは、Http クラスのプライベートインスタンスを作成し、先ほど作成したユーザーの user/authtoken 資格情報に基づいて Authorization HTTP ヘッダーを設定します。このヘッダーを HTTP リクエストに含めます。

constructor(private http: Http) {
        this.headers.append('Authorization', 'Basic ' + btoa(this.userName+":"+this.authToken));
        }

getTables()

この関数はテーブルのリストを返します。リストは、Authorization ヘッダーを含む HTTP GET リクエストを Connect Server のベース URL(http://localhost:8080/odata.rsc)に送信することで取得されます。

getTables(): Promise&lt;API_Table[]&gt; {
        return this.http.get(this.baseUrl, {headers: this.headers})
        .toPromise()
        .then(response => response.json().value )
        .catch(this.handleError);
        }

getColumns()

この関数は、tableName で指定されたテーブルのカラムリストを返します。$metadata エンドポイントはデフォルトで XML 形式のデータを返すため、Connect Server から JSON データを確実に取得するために URL に @json パラメータを渡します。JSON データを取得したら、ドリルダウンしてカラム名のリストを取得できます。

getColumns(tableName: string): Promise&lt;string[]&gt; {
        return this.http.get(`${this.baseUrl}/${tableName}/$metadata?@json`, {headers: this.headers})
        .toPromise()
        .then(response => response = response.json().items[0]["odata:cname"] )
        .catch(this.handleError);
        }

getTableDataByColumns(tableName:string, columnList: string)

この関数は、指定されたテーブルとカラムのデータ行を返します。URL に tableName を渡し、カラムのリスト(カンマ区切りの文字列)を $select URL パラメータの値として渡します。特定のカラムが指定されていない場合は、$select URL パラメータを使用せずにすべてのカラムをリクエストします。

getTableDataByColumns(tableName:string, columnList: string): Promise<Object[]>
            {
            if (columnList) {
            return this.http.get(`${this.baseUrl}/${tableName}/?$select=${columnList}`, {headers: this.headers})
            .toPromise()
            .then(response => response = response.json().value )
            .catch(this.handleError);
            } else {
            return this.http.get(`${this.baseUrl}/${tableName}/`, {headers: this.headers})
            .toPromise()
            .then(response => response = response.json().value )
            .catch(this.handleError);
            }
            }

getAllTableDataById(tableName:string, idColumn:string, idValue:string)

この関数は、指定された ID カラムと値に基づいて、指定されたテーブルのデータ行を返します。URL に tableName を渡し、ID カラムと値を使用してメインテーブルの特定のエントリに関連するデータをリクエストします。

getAllTableDataById(tableName:string, idColumn:string, idValue:string): Promise<Object[]>
            {
            return this.http.get(`${this.baseUrl}/${tableName}(${idColumn}='${idValue}')`, {headers: this.headers})
            .toPromise()
            .then(response => response = JSON.parse('[' + response['_body'] + ']'))
            .catch(this.handleError);
            }

src/app/dashboard.component.ts


この TypeScript ファイルでは、SPA のイベントに反応する関数を定義しています。これらの関数内で AppService の関数を呼び出し、その結果を使用して SPA のさまざまな要素を表示します。これらの関数は比較的単純で、必要に応じて異なる変数に値を割り当てています。

ngOnInit()

この関数では、AppServicegetTables 関数を呼び出します。getTables は Connect Server テーブルクエリから生の data オブジェクトを返すため、各結果からオブジェクト全体ではなく name フィールドのみを利用可能なテーブルの配列にプッシュする必要があります。

ngOnInit(): void {
        this.appService
        .getTables()
        .then( tables => {
        for (let tableObj of tables) {
        this.tableNames.push( tableObj.name )
        }
        });
        }

tableChanged()

この関数は、ユーザーが SPA のドロップダウンメニューからテーブルを選択するたびに呼び出されます。この関数は Connect Server を呼び出して指定されたテーブルのカラムリストを取得し、別のドロップダウンメニューに表示します。また、選択されたテーブルのデータも取得し、HTML テーブルに表示します。

tableChanged(): void {
        this.appService
        .getColumns(this.selectedTable)
        .then( columns => this.tableColumns = columns.sort() );
        this.appService
        .getTableDataByColumns(this.selectedTable, this.tableColumns)
        .then( data => this.tableData = data );
        }

subTableChanged()

この関数は、ユーザーがドロップダウンメニューから関連テーブルを選択するたびに呼び出されます。この関数は Connect Server を呼び出して指定されたテーブルのカラムリストを取得し、別のドロップダウンメニューに表示します。

subTableChanged(): void {
        this.appService
        .getColumns(this.selectedSubTable)
        .then( columns => this.subTableColumns = columns.sort() );
        }

rowClicked(keyValue: string)

この関数は、メインテーブルのデータ行がクリックされるたびに呼び出されます。メインテーブルで選択されたカラムに基づいて行の ID 値をキャプチャし、選択された ID に基づいて関連テーブルからデータを取得するために Connect Server を呼び出します。取得されたデータは HTML テーブルに表示されます。

rowClicked(keyValue: string): void {
        columnList = this.selectedColumns.join(',');
        this.appService
        .getTableData( this.selectedTable, columnList )
        .then( data => this.tableData = data );
        }

シングルページアプリケーションの実行

データへの接続を設定し、SPA のソースファイルを確認したら、シングルページアプリケーションを実行する準備が整いました。SPA を実行するには、マシンに node.js と npm がインストールされている必要があります。サンプルダウンロードには、設定済みの package.json ファイルが含まれています。SPA のルートディレクトリでコマンドラインから npm install を実行することで、必要なモジュールをインストールできます。SPA を起動するには、同じディレクトリで npm start を実行します。

SPA が起動すると、タイトルとテーブルを選択するドロップダウンメニューが表示されます。テーブルのリストは Connect Server から取得され、Connect Server の設定時にリソースとして追加したすべてのテーブルが含まれています。

テーブルを選択すると、カラムのドロップダウンが表示され、テーブルとサブテーブルを関連付けるキーカラムを選択できます。

メインテーブルとキーカラムを選択したら、関連するサブテーブルを選択できます。

サブテーブルを選択すると、カラムのドロップダウンが表示され、テーブルとサブテーブルを関連付けるキーカラムを選択できます。

テーブルとカラムを選択すると、メインテーブルのデータが表示されます。HTML テーブルの行をクリックすると、クリックしたエントリに対応する関連ラインアイテムをサブテーブルから取得できます。

無料トライアルと詳細情報

動的な Web ページでデータベースデータに接続する基本的な例をご覧いただきました。Connect Server ページで詳細情報を確認し、Connect Server をダウンロードしてください。QuickBooks Online などのオンプレミスおよびクラウドベースのデータベース、アプリケーション、サービスからのライブデータを使用して、動的な Web ページの構築を始めましょう。ご不明な点がございましたら、サポートチームがお手伝いいたします。

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

CData API Server の無料トライアルをダウンロード:

今すぐダウンロード