7 July 2008
ページ ツール |
実際に試すには、コードをご自分の開発環境のWebルートにダウンロードして解凍してください(ファイルはRIAフォルダに入っています)。
注意:この記事の初出はSitePoint*です。
リッチインターネットアプリケーション(RIA)は、Macromedia(現在はAdobe)によって2002年に造られた用語です。RIAはWebアプリケーションです。Webブラウザ内で実行しますが、デスクトップアプリケーションのように動作するのが特徴です。GatnerアナリストのMark Driver、Ray ValdesおよびGene Phiferは、RIAを「Webの次なる進化* 」[1](PDF、56KB)と位置付けています。
RIAが他の従来のWebアプリケーションと異なる点は次のとおりです。
RIAを作成するには、Adobe Flash、Adobe Flex、Ajaxなどの様々なテクノロジを使用できます。ColdFusion 8では、新しいツールを使用してRIAをすばやく簡単に作成できます。Flashプラットフォームに基づくRIAを作成することも、従来の単純な HTML* [2]でAjaxを使用するという方法でRIAを実現することもできます。この記事では、Ajaxの新しいタグや関数を紹介します。実際にAdobe ColdFusion 8で初めてのRIAとして単純なユーザ管理アプリケーションを作成する方法を示します。
まず、ColdFusionのデータソースを設定する必要があります。このアプリケーションでは、ColdFusion 8の別の機能として Apache [3] Derbyデータベースを使用します。Apache Derby は、 アプリケーション内に埋め込むことができるJava* [4]リレーショナルデータベース管理システムです。Derbyをデータベースとして使用すると、追加のソフトウェアのインストールを最小限にして、複数のオペレーティングシステム間の互換性を確保できます。
最初の手順として、データベースから情報を読み取るためのデータソースを設定します。データソースを設定するには、次の手順に従います。
{Webルートへのパス}/RIA/database/RIAに設定します。デモアプリケーションのテストランの準備ができました。ブラウザでhttp://{Webルート}/RIAを参照すると、図1のようなページが表示されます。
グリッドは書式化されています。データの行は交互に色が変わり(ゼブラストライプ)、ページ操作が可能です。列もソート可能です。試しに、列の見出しをクリックしてください。
ユーザの詳細ウィンドウを表示するには、「New User」ボタンをクリックするか、グリッドの行をダブルクリックします。図2に示すUser Informationダイアログボックスが表示されます。
フォームはモーダルウィンドウ内に表示されます。つまり、このウィンドウが表示されている間は、基のページを操作できません。ユーザ情報を入力または変更し、「Save User」をクリックします。ウィンドウが閉じて、データグリッドに変更が反映されます。
このページを作成するために使用したコードを詳しく見てみましょう。最初にグリッドを表示するコードを検討します。このコードはindex.cfmファイルにあります。
通常、ソート可能な列やページコントロールを含むグリッドまたはテーブルを表示するには、大量のコードを必要とします。それは、他のフレームワークを使用した場合でも同様です。しかし、ColdFusion 8では、次のColdFusionタグを使用するだけで済みます。
<cfgrid name="userGrid" format="html" pagesize="5" preservePageOnSort="true" bind="cfc:com.user.UserService.getAllUsers( {cfgridpage}, {cfgridpagesize}, {cfgridsortcolumn}, {cfgridsortdirection})" sort="true" stripeRows="true">
<cfgridcolumn name="USERID" header="ID" display="false" />
<cfgridcolumn name="FIRSTNAME" header="First Name" width="200" />
<cfgridcolumn name="LASTNAME" header="Last Name" width="300" />
<cfgridcolumn name="EMAILADDRESS" header="Email" width="220" />
<cfgridcolumn name="PHONE" header="Phone" />
</cfgrid>
これだけです。ご覧のように、 JavaScript* [5]は必要ありません。HTMLすらも必要ありません。必要なのは数行のColdFusionコードだけです。cfgridタグの各属性を見てみましょう。
name-グリッドの名前を指定する属性です。また、JavaScript内でのグリッドの参照名です。format-構築するグリッドの書式を指定します。AJAXグリッドを作成するには、上の例で示したように、"HTML"を指定します。pageSize-各ページに表示するアイテムの数を定義します。bind-グリッドに入れるデータの取得先を指定します。上の例では、com/user/ディレクトリにあるUserServiceという名のColdFusionコンポーネント(CFC)のgetAllUsersというメソッドを使用することを指示しています。ColdFusionでCFCを呼び出す場合、ドット表記を使用してCFCへのパスを指定します。また、getAllUsersメソッドには引数として{cfgridpage}、{cfgridpagesize}、{cfgridsortcolumn}および{cfgridsortdirection}を渡します。これらの変数は、グリッドの現在の状態と、グリッドのソートやページ付けに必要な情報の取得方法を定義します。sort-列がソート可能であることを示します。preservePageOnSort-ユーザがデータをソートしたときに現在のページを再描画するかどうかを指定します。例えば、ユーザがページ2を表示しているときにデータをソートした場合、新しいデータセットのページ2を表示するかどうかを決定します。この値を設定しない場合は、グリッドがソートされるたびにグリッドはページ1にリセットされます。stripeRows-行の色を交互に変えることを指定します。グリッドの外観と動作を指定するための属性は他にもたくさんあります。詳しくは、cfgrid要素に関する製品ドキュメントを参照してください。
次の<cfgridcolumn>タググループでは、表示する列に関する情報を指定します。
name-この列に表示する要素(クエリ列)の名前です。header-列の見出しに表示するテキストです。width-列の幅を指定します。注意:userIDは表示されません。
データソースはuserId列を取得しますが、この列はdisplay="false"属性によって非表示になります。userIdの値により、データベース内のユーザを一意に識別します。選択した行でこの値を使用することにより、すべてのユーザ情報を取得してUser Informationウィンドウに表示することができます。
グリッドの列の外観と動作を指定するための属性は他にもたくさんあります。詳しくは、<cfgridcolumn>に関する製品ドキュメントを参照してください。
次に、<cfgrid>のbind属性で参照されるCFCを見てみましょう。ここには個別のユーザを取得して保存するためのメソッドがあります。すべてのユーザを取得して<cfgrid>に挿入するためのメソッドもあります。このコードを詳しく検討しましょう。
queryConvertForGridメソッドのコードは次のとおりです。
<cffunction name="getAllUsers" output="false" access="remote" returntype="struct">
<cfargument name="cfgridpage">
<cfargument name="cfgridpageSize">
<cfargument name="cfgridsortcolumn" />
<cfargument name="cfgridsortdirection" />
<cfset var qRead="">
<cfquery name="qRead" datasource="ria">
SELECT userId,firstName,lastName,emailAddress,phone
FROM users
<cfif len(arguments.cfgridsortcolumn) and len(arguments.cfgridsortdirection)>
ORDER BY #arguments.cfgridsortcolumn# #arguments.cfgridsortdirection#
<cfelse>
ORDER BY lastName ASC
</cfif>
</cfquery>
<cfreturn queryConvertForGrid(qRead, cfgridpage, cfgridpageSize) />
</cffunction>
この単純な関数では次の4つの引数を使用します。
cfgridpagecfgridpagesizecfgridsortcolumncfgridsortdirectionこれらの引数は、<cfgrid>のbind属性で指定した引数と一致します。
<cffunction>タグについては、access属性が重要です。Ajaxを使用してCFCからデータを取得する場合は、呼び出す関数のaccess属性を"remote"に設定する必要があります。
関数はデータベースのユーザテーブルに対して簡単なクエリを実行し、引数としてcfgridsortcolumnとcfgridsortdirectionを使用して結果をソートします。この両方の値が空の文字列である場合は、姓を使用して結果がソートされます。
最後に、<cfreturn>を使用して、queryConvertForGrid関数からの戻り値を返します。queryConvertForGridはColdFusionのネイティブ関数です。クエリの結果を受け取って書式化し、<cfgrid>に自動的に挿入するための専用関数です。この関数では、次の3つの引数を使用します。
この関数は、<cfgrid>でデータを簡単に解釈して表示できるように書式化されたColdFusion構造を返します。
次に詳細ウィンドウを開くためのコードを検討します。まず、index.cfmの次の2行のコードをご覧ください。
<cfset ajaxOnLoad("initGrid") />
<cfajaximport tags="cfform" />
最初の行は、Ajaxを最初に呼び出したときに、JavaScript関数のinitGridを実行することを示します。2番目の行は、ColdFusion要素を使用する場合に、メインページにライブラリを読み込む必要があることを示します。
JavaScript関数のinitGridは単にグリッドにリスナーを追加します。リスナーが追加されると、行をダブルクリックしたときにJavaScript関数のshowUserが呼び出されます。initGridのコードは次のとおりです。
function initGrid(){
var grid = ColdFusion.Grid.getGridObject("userGrid");
grid.on("rowdblclick", showUserForm);
}
initGridメソッドの最初の行は、グリッドのインスタンスとしてuserGridを返します。この名前は、<cfgrid>のname属性に指定した値です。
2番目の行は、rowdblclickイベントのリスナーを設定し、このイベントが発生したときにshowUserForm関数を呼び出すことを指定します。ColdFusionでは、実際にはExt JS JavaScriptライブラリを使用してグリッドを作成します。したがって、rowdblclickはグリッドオブジェクトにネイティブなイベントです。Ext JSグリッドオブジェクトについて詳しくは、ExtJSサイト*[6]を参照してください。
行をダブルクリックしたときにグリッドでshowUserFormを実行することを指定したので、次に詳細ウィンドウを表示するコードを見てみましょう。
まず、showUserFormメソッドのコードは次のとおりです。
function showUserForm(){
var userId = ColdFusion.getElementValue("userGrid", "userGridForm", "userId");
var url = "userForm.cfm?UserId="+userId ;
ColdFusion.navigate(url, "userWin");
ColdFusion.Window.show("userWin");
}
上のコードの1行目では、選択された行のuserIdを取得します。ColdFusion.getElementValueでは次の3つの引数を使用します。
この例では、userGridFormフォームのuserGridコントロールからuserId属性を取得することを指示しています。
次に変数urlを設定します。この変数にユーザが参照するURLが保存されます。URLのパラメータとしてuserIdを追加します。このURLは次の行で使用されます。次の行では、このURLへのhttp要求を行い、結果をuserWinという名前の<cfwindow>要素内に表示します。ColdFusion.navigateメソッドを使用してページ上の任意のHTML要素(divなど)に入力することができます。最終行では、<cfwindow>を表示します。
次は、<cfwindow>タグを使用してJavaScriptベースのポップアップウィンドウを作成するコードを見ましょう。
<cfwindow name="userWin" title="User Information" initShow="false" modal="true" center="true"></cfwindow>
実に簡単です。各属性を確認します。
title - ウィンドウの上部に表示されるテキストを指定します。initShow-ウィンドウを最初に表示するかどうかを指定します。modal-ポップアップウィンドウをモーダルにするかどうかを指定します。モーダルウィンドウにすると、ユーザは基のページを操作できなくなります。center-trueに設定すると、ポップアップウィンドウが画面中央に表示されます。グリッドの外観と動作を指定するための属性は他にもたくさんあります。詳しくは、<cfwindow>要素に関する製品ドキュメントを参照してください。
次は、フォームに関するコードを見てみましょう。
ユーザフォームを作成するコードは次のとおりです。
<cfparam name="url.userId" default="" />
<cfset user = createObject("component","com.user.UserService").getUser(url.userid) />
<cfform name="userForm">
<cfinput type="hidden" name="userId" value="#url.userId#" />
<div class="formElement">
<label for="firstName">First Name</label>
<cfinput id="firstName" name="firstName" value="#user.firstName#" />
<div id="firstNameError" class="error"></div>
</div>
<div class="formElement">
<label for="lastName">Last Name</label>
<cfinput id="lastName" name="lastName" value="#user.lastName#" />
<div id="lastNameError" class="error"></div>
</div>
<div class="formElement">
<label for="emailAddress">Email Address</label>
<cfinput id="emailAddress" name="emailAddress" value="#user.emailAddress#" />
<div id="emailAddressError" class="error"></div>
</div>
<div class="formElement">
<label for="phone">Phone</label>
<cfinput id="phone" name="phone" value="#user.phone#" />
<div id="phoneError" class="error"></div>
</div>
<div><cfinput name="submit" type="button" value="Save User" onclick="submitForm()"><cfinput type="button" name="cancel" value="Cancel" onclick="ColdFusion.Window.hide('userWin')"></div>
</cfform>
特に複雑な点はありません。
まず、<cfparam>を使用してURL変数を空の文字列に初期化します。次の行で、UserServiceオブジェクトのインスタンスを作成し、getUserメソッドを呼び出してユーザ変数userIdを渡します。
残りのコードでは、データベースから取得した情報をフォームに入力するだけです。これが新規ユーザである場合は、データベースから取得された結果は空の文字列になります。したがって、このフォームは空になります。
「Submit」ボタンと「Cancel」ボタンの動作について付け加えます。「Submit」ボタンは、submitFormというJavaScript関数を呼び出します。「Cancel」ボタンは、単にColdFusion.Window.hide("userWin")を呼び出し、<cfwindow>を非表示にします。各フォームフィールドの下に、空のdivがあり、idが"{formFieldName}Error"のように表示されています。このidでは、フォームの検証時に返されるエラーメッセージを表示します。
最後に、このページにはJavaScriptが含まれていません。このフォームはメインページ内にあるので、すべてのJavaScript参照はそこに格納できます。
index.cfmのsubmitForm関数を見てみましょう。
function submitForm() {
clearErrors();
ColdFusion.Ajax.submitForm("userForm", "userForm_submit.cfm", submitCallback, errorHandler);
この関数では、最初にclearErrorsメソッドを呼び出し、前回の使用時からのフォーム検証エラーがあれば、それをフォームからクリアします。上のコードの2行目では、ポストを実行します。ColdFusion.Ajax.submitFormメソッドはフォームuserFormにあるすべてのアイテムの値をURL(userForm_Submit.cfm)にポストします。サーバから応答が返されると、submitCallback関数が呼び出されます。エラーがある場合は、errorHandlerメソッドが実行されます。
次に、userForm_submit.cfmファイルを見てみましょう。このファイルでは、フォームを検証してユーザの詳細を保存します。
<cfsetting enablecfoutputonly="true" />
<cfset errors = StructNew() />
<cfif form.firstName EQ "">
<cfset errors["firstName"] = "You must enter a first name." />
</cfif>
<cfif form.lastName EQ "">
<cfset errors["lastName"] = "You must enter a last name." />
</cfif>
<cfif NOT isValid("email", form.emailAddress)>
<cfset errors["emailAddress"]= "You must enter a valid email address" />
</cfif>
<cfif NOT isValid("telephone",form.phone)>
<cfset errors["phone"] = "You must enter a valid phone number" />
</cfif>
<cfif structIsEmpty(errors)>
<cfset createObject("component","com.user.UserService").saveUser(argumentCollection = form) />
<cfelse>
<cfoutput><cfoutput>#serializeJSON(errors)#</cfoutput></cfoutput>
</cfif>
<cfsetting enablecfoutputonly="false" />
このページには、検証エラーに関するすべての情報を保持する変数errorを作成してあります。この例で適用する検証は単純です。firstNameとlastNameが空の文字列ではないこと、emailAddressとphoneに、それぞれ有効な電子メールアドレスと電話番号が含まれていることを確認します。
データの検証が済んで変数errorsが空である場合は、そのデータをデータベースに安全に保存できます。再度、UserServiceのインスタンスを作成し、saveメソッドを呼び出して、フォームのスコープをargumentCollectionとして渡します。saveメソッドには、新規ユーザ(追加する必要あり)と既存ユーザ(更新する必要あり)を判別するロジックが含まれています。
変数errorsが空でない場合は、データにエラーがあります。問題が発生したことをメインページが確認できる方法で、これらのエラーを渡す必要があります。このような場合は、JSON(JavaScript Object Notation)を使用するのが最適です。幸い、ColdFusion 8にはネイティブ関数としてserializeJSONがあり、ColdFusionオブジェクトをJSONストリングとしてシリアル化できます。
この関数への呼び出しを<cfoutput>タグにラップすることにより、シリアル化されたストリングとして変数errorsを返します。別のColdFusion関数deserializeJSONでは、JSONストリングを受け取って対応するColdFusionデータ構造を返します。
このページの結果の処理については、もう一度index.cfmに戻り、submitCallbackメソッドのコードを確認しましょう。
function submitCallback(response){
var errors = ColdFusion.JSON.decode(response);
var valid = true;
for(i in errors){
document.getElementById(i+"Error").innerHTML = errors[i];
valid = false;
}
if(valid){
ColdFusion.Window.hide("userWin");
ColdFusion.Grid.refresh("userGrid", true);
}
}
ご覧のように、submitCallback関数は1つの引数を使用します。この引数は、フォームを送信したときにサーバから返される応答です。最初に、返されたJSON文字列をColdFusion.JSON.decodeを使用してデコードします。これにより、JSON文字列をJavaScriptオブジェクトに変換します。JavaScriptオブジェクトを受け取ってJSON文字列を返すColdFusion.JSON.encodeという関数もあります。
errors JavaScriptオブジェクトにエラーがある場合は、そのオブジェクトの要素をループオーバーし、フォームフィールドの対応するdivのinnerHTMLを設定します。これらは、clearErrorsメソッドを呼び出したときにクリアされる同じdivです。エラーが返された場合は、変数validをfalseに設定します。
エラーが返されず、フォームが有効である場合は、ColdFusion.Window.hide("show")メソッドで<cfwindow>を正常に閉じることができます。最後に、ColdFusion.Grid.refreshを使用してグリッドを更新し、加えられた変更をグリッドに反映します。
次に、フォームを表示して新しいユーザを作成する作業だけが残りました。
「New User」ボタンをクリックして新規ユーザを作成することができます。このボタンでは、JavaScript関数newUserを呼び出します。
function newUser(){
var url = "userForm.cfm" ;
ColdFusion.navigate(url, "userWin");
ColdFusion.Window.show("userWin");
}
上のコードを見ると、この関数はshowUserForm関数に似ています。ただし、URLにuserIdは渡しません。これにより、<cfwindow>を開いたときに、空のフォームが表示されます。
このコード内のJavaScriptは最小限ですが、ソースコードにはより多くのJavaScriptが見つかります。ColdFusionのAjaxコンポーネントのいずれかを使用する場合は、そのコンポーネントが動作するために必要なJavaScriptが自動的に呼び出されます。
以上、多くの事項を扱ったようですが、実際にはブラウザ間の互換性やユーザを一覧表示して管理するためのリッチインターフェイスを紹介したにすぎません。グリッドにはソート可能な列とページコントロールが含まれること、Ajax呼び出しを通じてグリッドの更新とフォームの表示および処理を行うことを示しました。
これらの作業のすべてを、4つの比較的小さなColdFusionファイルと約30行のJavaScriptで実現しました。このように、ColdFusionではJavaScript、Ajax、ブラウザの互換性の問題などに悩まされることなく、RIAを容易に作成することができます。
ここで触れたColdFusionのAjax機能はほんの一部です。ColdFusion 8でAjaxアプリケーションを作成する方法について詳しくは、『ColdFusion Developer's Guide』を参照してください。
記事の注