実装例:登録画面を作る¶
この項では、スマートフォンでTODOを登録する画面の実装例を紹介します。
項目
前提条件¶
intra-mart Accel Platform をインストールし、初期設定までが完了していること。
ベースモジュールにスクリプト開発フレームワーク、およびIM-Mobile Frameworkモジュールを含めて環境を作成してください。実行環境は単体テスト用で作成してください。
下準備 テーブル作成¶
以下手順を行う前に、以下のテーブルを作成してください。
mfw_sample
列名 データ型 主キー NOT NULL 説明 id VARCHAR(20) ○ ○ レコードのID user_cd VARCHAR(20) ○ 登録ユーザID user_nm VARCHAR(20) ○ 登録ユーザ名 limit_date VARCHAR(20) TODOの期限 title VARCHAR(100) TODOのタイトル comment VARCHAR(1000) コメント progress NUMBER(3) 進捗度 complete VARCHAR(1) 完了/未完了 priority VARCHAR(1) 重要度 timestmp VARCHAR(20) タイムスタンプ ※その他のデータベースの場合は環境に合わせて調整してください。
画面を表示できるようにする¶
ソースの準備と配置¶
まず、以下2点のファイルを作成します。
%CONTEXT_PATH%/WEB-INF/jssp/src/sample/mobile_fw/sp_store.js
function init(request) { }%CONTEXT_PATH%/WEB-INF/jssp/src/sample/mobile_fw/sp_store.html
<imart type="head"> <title>TODO登録</title> </imart> <div data-role="page" id="main"> <imart type="spHeaderWithLink" headerText="TODO登録" /> <div class="ui-content" role="main"> </div> <imart type="spCommonFooter" dataPosition="fixed" /> </div>spHeaderWithLink - ヘッダ部左端に、任意のページに遷移のボタンを備えたヘッダを表示します。
spCommonFooter - フッタ部にHOMEボタンとログアウトボタンを表示します。
jqueyMobile1.4.5を読み込むようにする¶
ライブラリ群の設定を行います。本サンプルでは /sample/sp 以下すべてに jQueryMobile1.4.5 が読み込まれるように設定します。
%CONTEXT_PATH%/WEB-INF/conf/theme-full-theme-path-config/im_mobile_sample.xml
<theme-full-theme-path-config xmlns="http://www.intra-mart.jp/theme/theme-full-theme-path-config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.intra-mart.jp/theme/theme-full-theme-path-config theme-full-theme-path-config.xsd"> <path client-type="sp" libraries-version="iap-8.0.11">/sample/sp/.*</path> </theme-full-theme-path-config>
メニューから遷移できるようにする¶
次にルーティングの設定を行います。
%CONTEXT_PATH%/WEB-INF/conf/routing-jssp-config/im_mobile_sample.xml
<?xml version="1.0" encoding="UTF-8"?> <routing-jssp-config xmlns="http://www.intra-mart.jp/router/routing-jssp-config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.intra-mart.jp/router/routing-jssp-config routing-jssp-config.xsd "> <authz-default mapper="welcome-all" /> <file-mapping path="/sample/sp/store" client-type="sp" page="/sample/mobile_fw/sp_store" /> </routing-jssp-config>コラム
ルーティングの詳細については ルーティング を参照してください。 file-mapping要素にclient-type=”sp”属性を付加するとクライアントタイプがスマートフォンの場合のみ使用可能なルーティングを設定できます。
メニューの作成¶
再起動してメニューの設定を行います。
PCブラウザからテナント管理者でログインし、「メニュー設定」画面を表示します。
グローバルナビ(スマートフォン用)を選択し、新規メニューグループ「テストTODO」を作成します。
新規メニューアイテムを作成します。
メニューアイテム名を「TODO登録」とし、URLを”sample/sp/store”とします。
認可の設定¶
認可を設定します。
「権限設定」ボタンをクリックし権限設定(グローバルナビ(スマートフォン用))を表示します。
「権限設定を開始する」ボタンをクリックします。
テストTODOの権限の「参照」権限を認証済みユーザに付与します。
コラム
- 認可の詳細については 認可 を参照してください。
画面を表示する¶
作成したプレゼンテーションページをメニューから表示します。
クライアントタイプをスマートフォン版へ切り替え、スマートフォン版グローバルナビを表示します。
メニューから「テストTODO」を選択すると、先ほど作成されたメニュー「TODO登録」が表示されます。
TODO登録を選択します。目的の画面を表示できました。
コラム
この項目では、下記のポイントを確認しました。
- ファイルマッピングにclient-type=”sp”属性を付加することでスマートフォン用のルーティングが設定できる
- スマートフォン用グローバルナビにメニューを表示するには、メニューカテゴリ「グローバルナビ(スマートフォン用)」に設定する
画面に要素を配置する¶
<div class=”ui-content” role=”main”>内に要素を配置します。例としてテキストボックスとラベルを配置してみます。ラベルを配置するには<imart type=”spFieldContain”>タグを使用します。
ファンクションコンテナ(HTML)
<imart type="spFieldContain" label="TODO名" required="true"> <imart type="input" style="text" name="title" value=title /> </imart>マークアップ結果。テーマにより最適化されたテキストボックスが表示されました。
同様に他の要素も配置していきます。
spDatePicker–日付文字列を参照入力するためのインタフェースを提供します。
<imart type="spFieldContain" label="期限" required="true"> <imart type="spDatePicker" name="limit_date" value=limit_date /> </imart>textarea–テキストエリアを提供します(PC版共通)。
<imart type="spFieldContain" label="コメント"> <imart type="textarea" name="comment" value=comment /> </imart>spControlGroup–フォーム要素をグループ化します。
spRadioButton–jQuery mobileで最適化されたラジオボタンを提供します。
<imart type="spControlGroup" label="重要度"> <imart type="spRadioButton" name="priority" id="radio1" value="0" label="低"></imart> <imart type="spRadioButton" name="priority" id="radio2" value="1" label="中"></imart> <imart type="spRadioButton" name="priority" id="radio3" value="2" label="高"></imart> </imart>spSlider–スライダーを提供します。
<imart type="spFieldContain" label="進捗"> <imart type="spSlider" name="progress" value=progress min="0" max="100" /> </imart>spToggleSwitch–トグルスイッチを提供します。
<imart type="spFieldContain" label="完了"> <imart type="spToggleSwitch" name="complete" selected=complete onLabel="完了" offLabel="未完了" onValue="1" offValue="0" /> </imart>マークアップ結果。各要素が表示されました。
その他使用可能な要素についてはAPIリストを参照してください。
コラム
この項目では、下記のポイントを確認しました。
- フォーム要素は<div class=”ui-content” role=”main”>内に配置する
- ラベルを与える場合は<imart type=”spFieldContain”>タグを使用する
登録処理を実装する¶
登録処理用のファンクションコンテナを新規作成します。
%CONTEXT_PATH%/WEB-INF/jssp/src/sample/mobile_fw/sp_store_do.js
function init(request) { //ユーザプロファイル情報を取得します。 var userProfile = Contexts.getUserContext().userProfile; //登録データを作成します。 var insertObject = { id:Identifier.get(), //レコードのユニークID user_cd:userProfile.userCd, //登録ユーザCD user_nm:userProfile.userName, //登録ユーザ名 title:request.title, //TODOのタイトル limit_date:request.limit_date, //TODOの期日 comment:request.comment, //コメント progress:parseInt(request.progress),//進捗度 complete:request.complete, //完了or未完了 priority:request.priority, //重要度 timestmp:DateTimeFormatter.format("yyyy/MM/dd HH:mm", new Date()) //タイムスタンプ(yyyy/MM/dd HH:mm) }; //トランザクションを開始します。 Transaction.begin(function() { // データの保存を行います var result = new TenantDatabase().insert("mfw_sample", insertObject); if(result.error){ //エラー時、ロールバックしエラー画面へ遷移します。 Transaction.rollback(); Transfer.toErrorPage({ title: 'エラー', message: 'データ登録時にエラーが発生しました。', detail: result.errorMessage }); } }); //画面を再表示します。 forward("sample/mobile_fw/sp_store", request); }コラム
- データベースを使用したプログラミングの詳細については データベース を参照してください。
im_mobile_sample.xmlに登録処理用のルーティングを追加します。
<file-mapping path="/sample/sp/store/insert" client-type="sp" page="/sample/mobile_fw/sp_store_do" />画面にFormタグと「登録」ボタンを配置します。 formタグのaction属性は先ほど設定したルーティングのパスと同様にします。
<div class="ui-content" role="main"> <form id="storeForm" name="storeForm" method="POST" action="sample/sp/store/insert" data-ajax="false"> <imart type="spFieldContain" label="TODO名" required="true"> <imart type="input" style="text" name="title" value=title /> </imart> ... <imart type="spFieldContain" label="完了"> <imart type="spToggleSwitch" name="complete" selected=complete onLabel="完了" offLabel="未完了" onValue="1" offValue="0" /> </imart> <a class="ui-btn ui-btn-b ui-corner-all" id="storeButton">登録</a> </form> </div>コラム
- リンクにui-btnクラスを指定するとリンクをボタン表示します。
- テーマを指定するにはクラス属性にui-btn-bのように「ui-btn-」の後にテーマを指定します。
- ボタンを角丸にするにはui-corner-allクラスを指定します。
- 「data-role=”button”」を指定してもボタンを表示しますが、jQuery Mobile1.4以降では非推奨です。
- リンクまたはFORM要素にdata-ajax=”false”属性を付加することで明示的にAjax画面遷移をキャンセルできます。
最後に「登録」ボタン押下時のイベントを実装します。このとき、記述箇所は<div data-role=”page”>内に実装することに気を付けてください。<div data-role="page" id="main"> <script> (function($){ $('#main').on("pagecreate", function() { $("#storeButton").tap(function() { $("#storeForm").submit(); }); }); })(jQuery); </script>注意
jQuery Mobileでは、Ajaxを使って画面遷移をする場合遷移先画面の<div data-role=”page”>要素のみ取得し、表示中画面に挿入します。そのため、<HEAD>タグ内にスクリプト、およびスタイルシートを宣言すると画面遷移時に読み込まれないため、不正動作をする場合があります。サーバを再起動して画面を再表示します。 「登録」ボタン押下時、登録処理を経て画面が再表示されます。
コラム
この項目では、下記のポイントを確認しました。
- フォームを送信するにはformタグのaction属性にルーティングのパスを与える
入力チェック処理を実装する(サーバサイド)¶
例としてタイトルと日付の入力チェックを実装します。
コラム
以下のメッセージがある前提として説明します。CAP.Z.IWP.MFW.SAMPLE.TITLE=タイトルCAP.Z.IWP.MFW.SAMPLE.LIMIT_DATE=期限メッセージプロパティは各環境に合わせて設定してください。メッセージプロパティの詳細については 多言語 を参照してください。バリデーションルールを定義するため、以下のファイルを作成します。
- %CONTEXT_PATH%/WEB-INF/jssp/src/sample/mobile_fw/validator.js
var validateRule = { "title": { caption:"CAP.Z.IWP.MFW.SAMPLE.TITLE", required:true, maxlength:20 }, "limit_date": { caption:"CAP.Z.IWP.MFW.SAMPLE.LIMIT_DATE", required:true, date:true } };
sp_store_do.jsのinit関数にアノテーションを追加します。@validate には利用するバリデーションルールのパスを``@onerror`` には入力チェックエラー時に実行する関数名を指定します。/** * @validate sample/mobile_fw/validator#validateRule * @onerror handleErrors */ function init(request) {
- 入力チェックエラー時に実行する関数「handleErrors」をsp_store_do.jsに追加します。
function handleErrors(request, validationErrors) { Transfer.toErrorPage({ title: 'エラー', message: '入力チェックエラーが発生しました。', detail: validationErrors.getMessages() }); }
マークアップ結果。タイトルと日付未入力の状態で「登録」ボタンをクリックすると、登録処理が呼出されず入力チェックエラー処理が呼出され、エラー画面へ遷移します。コラム
JSSP Validatorの詳細については JSSP Validator を参照してください。
コラム
この項目では、下記のポイントを確認しました。
- 入力チェックのルールはバリデーションルールで定義する
- 入力チェックを実装するにはチェック対象の関数にアノテーションを定義する
入力チェック処理を実装する(クライアントサイド)¶
sp_store.htmlにimuiValidationRuleタグを追加します。rule属性に 入力チェック処理を実装する(サーバサイド) で作成したvalidate.jsのパスを、rulesName属性とmessagesName属性にそれぞれクライアントJS内で使用するオブジェクト名を定義します。
プレゼンテーションページ(HTML)
<div data-role="page" id="main"> <imart type="imuiValidationRule" rule="sample/mobile_fw/validator#validateRule" rulesName="rules" messagesName="messages" /> <script> (function($){ ...「登録」ボタン押下時のスクリプト処理を修正します。
プレゼンテーションページ(HTML)
<script> (function($){ $('#main').on("pagecreate", function() { //登録ボタン押下時のイベント $("#storeButton").tap(function() { //入力チェック実行 if (imspValidate('#storeForm', rules, messages)) { //正常時 imspAlert('入力エラーはありませんでした'); $("#storeForm").submit(); } else { imspAlert('入力エラーが発生しました', 'エラー'); } return false; }); }); })(jQuery); </script> マークアップ結果。タイトルと日付未入力の状態で「登録」ボタンをクリックすると、エラーダイアログが表示され警告が出力されます。コラム
エラー仕様の詳細は、 エラー処理 を参照してください。
コラム
この項目では、下記のポイントを確認しました。
- クライアントサイドで入力チェックを実装するには <imart type=”imuiValidationRule”>タグを定義する
- 入力チェックを実行するにはimspValidate関数を使う
非同期で登録処理を実行する¶
sp_store_do.jsのinit関数の処理を一部修正します。
ファンクションコンテナ(サーバサイドJavaScript)
var resultObject; Transaction.begin(function() { // データの保存を行います var result = new TenantDatabase().insert("mfw_sample", insertObject); if(result.error){ Transaction.rollback(); //Transfer.toErrorPage({ // title: 'エラー', // message: 'データ登録時にエラーが発生しました。', // detail: result.errorMessage // }); resultObject = { error:true, errorMessage:"データ登録時にエラーが発生しました。", detailMessages:["管理者にお問い合わせください。"] }; } else { resultObject = { error:false, errorMessage:"", successMessage:"登録が完了しました。" }; } }); var response = Web.getHTTPResponse(); response.setContentType('application/json; charset=utf-8'); response.sendMessageBodyString(ImJson.toJSONString(resultObject)); //画面を再表示します。 //forward("sample/mobile_fw/sp_store", request);コラム
- 非同期時はresponse.sendMessageBodyString関数で返却データを画面に返します。
- 返却するデータはImJson.toJSONString関数でJSON文字列化する必要があります。
「登録」ボタン押下時のスクリプト処理を修正します。
プレゼンテーションページ(HTML)
<script> (function($){ $('#main').bind("pagecreate create", function() { // Formの2度クリック防止 $('#storeForm').imspDisableOnSubmit(); $("#storeButton").tap(function() { if (imspValidate('#storeForm', rules, messages)) { //Ajaxでのデータ送信 imspAjaxSend('#storeForm', 'POST', 'json'); //バリデーションのリセット imspResetForm('#storeForm'); } else { imspAlert('入力エラーが発生しました', 'エラー'); } return false; }); }); })(jQuery); </script> マークアップ結果。「登録」ボタン押下後にダイアログが表示され、登録処理が正常終了したことが確認できるようになりました。
コラム
この項目では、下記のポイントを確認しました。
- クライアントから非同期でリクエストを送信するにはimspAjaxSend関数を使う
- サーバから非同期で返信するにはresponse.sendMessageBodyString関数を使う
最終結果¶
%CONTEXT_PATH%/WEB-INF/jssp/src/sample/mobile_fw/sp_store.js
function init(request) { }
%CONTEXT_PATH%/WEB-INF/jssp/src/sample/mobile_fw/sp_store.html
<imart type="head"> <title>TODO登録</title> </imart> <div data-role="page" id="main"> <imart type="imuiValidationRule" rule="sample/mobile_fw/validator#validateRule" rulesName="rules" messagesName="messages" /> <script> (function($){ $('#main').on("pagecreate", function() { // Formの2度クリック防止 $('#storeForm').imspDisableOnSubmit(); //登録ボタン押下時のイベント $("#storeButton").tap(function() { //入力チェック実行 if (imspValidate('#storeForm', rules, messages)) { //Ajaxでのデータ送信 imspAjaxSend('#storeForm', 'POST', 'json'); //バリデーションのリセット imspResetForm('#storeForm'); } else { imspAlert('入力エラーが発生しました', 'エラー'); } }); }); })(jQuery); </script> <imart type="spHeaderWithLink" path="home" headerText="TODO登録" /> <div class="ui-content" role="main"> <form id="storeForm" name="storeForm" method="POST" action="sample/sp/store/insert" data-ajax="false"> <imart type="spFieldContain" label="TODO名" required="true"> <imart type="input" style="text" name="title" value=title /> </imart> <imart type="spFieldContain" label="期限" required="true"> <imart type="spDatePicker" name="limit_date" value=limit_date /> </imart> <imart type="spFieldContain" label="コメント"> <imart type="textarea" name="comment" value=comment /> </imart> <imart type="spControlGroup" label="重要度"> <imart type="spRadioButton" name="priority" id="radio1" value="0" label="低"></imart> <imart type="spRadioButton" name="priority" id="radio2" value="1" label="中"></imart> <imart type="spRadioButton" name="priority" id="radio3" value="2" label="高"></imart> </imart> <imart type="spFieldContain" label="進捗"> <imart type="spSlider" name="progress" value=progress min="0" max="100" /> </imart> <imart type="spFieldContain" label="完了"> <imart type="spToggleSwitch" name="complete" selected=complete onLabel="完了" offLabel="未完了" onValue="1" offValue="0" /> </imart> <a class="ui-btn ui-btn-b ui-corner-all" id="storeButton">登録</a> </form> </div> <imart type="spCommonFooter" dataPosition="fixed"/> </div>
%CONTEXT_PATH%/WEB-INF/jssp/src/sample/mobile_fw/sp_store_do.js
/** * @validate sample/mobile_fw/validator#validateRule * @onerror handleErrors */ function init(request) { //ユーザプロファイル情報を取得します。 var userProfile = Contexts.getUserContext().userProfile; //登録データを作成します。 var insertObject = { id:Identifier.get(), //レコードのユニークID user_cd:userProfile.userCd, //登録ユーザCD user_nm:userProfile.userName, //登録ユーザ名 title:request.title, //TODOのタイトル limit_date:request.limit_date, //TODOの期日 comment:request.comment, //コメント progress:parseInt(request.progress),//進捗度 complete:request.complete, //完了or未完了 priority:request.priority, //重要度 timestmp:DateTimeFormatter.format("yyyy/MM/dd HH:mm", new Date()) //タイムスタンプ(yyyy/MM/dd HH:mm) }; var resultObject; Transaction.begin(function() { // データの保存を行います var result = new TenantDatabase().insert("mfw_sample", insertObject); if(result.error){ Transaction.rollback(); resultObject = { error:true, errorMessage:"データ登録時にエラーが発生しました。", detailMessages:["管理者にお問い合わせください。"] }; } else { resultObject = { error:false, errorMessage:"", successMessage:"登録が完了しました。" }; } }); var response = Web.getHTTPResponse(); response.setContentType('application/json; charset=utf-8'); response.sendMessageBodyString(ImJson.toJSONString(resultObject)); } function handleErrors(request, validationErrors) { Transfer.toErrorPage({ title: 'エラー', message: '入力チェックエラーが発生しました。', detail: validationErrors.getMessages() }); }
%CONTEXT_PATH%/WEB-INF/jssp/src/sample/mobile_fw/validator.js
var validateRule = { "title": { caption:"CAP.Z.IWP.MFW.SAMPLE.TITLE", required:true, maxlength:20 }, "limit_date": { caption:"CAP.Z.IWP.MFW.SAMPLE.LIMIT_DATE", required:true, date:true } };
%CONTEXT_PATH%/WEB-INF/conf/routing-jssp-config/im_mobile_sample.xml
<?xml version="1.0" encoding="UTF-8"?> <routing-jssp-config xmlns="http://www.intra-mart.jp/router/routing-jssp-config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.intra-mart.jp/router/routing-jssp-config routing-jssp-config.xsd "> <authz-default mapper="welcome-all" /> <file-mapping path="/sample/sp/store" client-type="sp" page="/sample/mobile_fw/sp_store" /> <file-mapping path="/sample/sp/store/insert" client-type="sp" page="/sample/mobile_fw/sp_store_do" /> </routing-jssp-config>
%CONTEXT_PATH%/WEB-INF/conf/message/im_mobile_sample.properties
native2ascii コマンドを利用して、プロパティファイルを変換した結果を示します。
# CAP.Z.IWP.MFW.SAMPLE.TITLE=タイトル CAP.Z.IWP.MFW.SAMPLE.TITLE=\u30bf\u30a4\u30c8\u30eb # CAP.Z.IWP.MFW.SAMPLE.LIMIT_DATE=期限 CAP.Z.IWP.MFW.SAMPLE.LIMIT_DATE=\u671f\u9650