実装例:登録画面を作る¶
この項では、スマートフォンで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" data-theme="a"> <imart type="spHeaderWithLink" headerText="TODO登録" /> <div data-role="content"> </div> <imart type="spCommonFooter" dataPosition="fixed" /> </div>spHeaderWithLink - ヘッダ部左端に、任意のページに遷移のボタンを備えたヘッダを表示します。
spCommonFooter - フッタ部にHOMEボタンとログアウトボタンを表示します。
メニューから遷移できるようにする¶
次にルーティングの設定を行います。
<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 data-role=”content”>内に要素を配置します。例としてテキストボックスとラベルを配置してみます。ラベルを配置するには<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 data-role=”content”>内に配置する
- ラベルを与える場合は<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 data-role="content"> <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 data-role="button" data-theme="b" id="storeButton">登録</a> </form> </div>コラム
- リンクにdata-role=”button”属性を付加するとリンクをボタン表示します。
- リンク又はFORM要素にdata-ajax=”false”属性を付加することで明示的にAjax画面遷移をキャンセルすることができます。
最後に登録ボタン押下時のイベントを実装します。このとき、記述箇所は<div data-role=”page”>内に実装することに気を付けてください。<div data-role="page" id="main" data-theme="a"> <script> (function($){ $('#main').bind("pagecreate create", 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" data-theme="a"> <imart type="imuiValidationRule" rule="sample/mobile_fw/validator#validateRule" rulesName="rules" messagesName="messages" /> <script> (function($){ ...登録ボタン押下時のスクリプト処理を修正します。
プレゼンテーションページ(HTML)
<script> (function($){ $('#main').bind("pagecreate create", function() { //登録ボタン押下時のイベント $("#storeButton").tap(function() { //入力チェック実行 if (imspValidate('#storeForm', rules, messages)) { //正常時 imspAlert('入力エラーはありませんでした'); } else { imspAlert('入力エラーが発生しました', 'エラー'); } return false; }); }); })(jQuery); </script> マークアップ結果。タイトルと日付未入力の状態で登録ボタンを押下すると、エラーダイアログが表示され警告が出力されます。![]()
alt: 入力チェックエラー コラム
エラー仕様の詳細については ../../../im_ui/rules/error/index を参照してください。
コラム
この項目では、下記のポイントを確認しました。
- クライアントサイドで入力チェックを実装するには <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)); //request.resultMessage = {result:"success", message:"登録が完了しました。"}; //forward(Web.current(), 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" data-theme="a"> <imart type="imuiValidationRule" rule="sample/mobile_fw/validator#validateRule" rulesName="rules" messagesName="messages" /> <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('入力エラーが発生しました', 'エラー'); } }); }); })(jQuery); </script> <imart type="spHeaderWithLink" path="home" label="HOME" headerText="TODO登録" /> <div data-role="content"> <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 data-role="button" data-theme="b" 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