intra-mart Accel Platform / スクリプト開発モデル プログラミングガイド

第6版 2014-01-01

«  基本的な画面の作り方   ::   コンテンツ   ::   実装例:一覧画面を作る  »

実装例:登録画面を作る

この項では、スマートフォンで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」を作成します。

    ../../../../../_images/menugroup.PNG

新規メニューアイテムを作成します。

  • メニューアイテム名を「TODO登録」とし、URLを”sample/sp/store”とします。

    ../../../../../_images/menuitem1.PNG

認可の設定

認可を設定します。

  • 「権限設定」ボタンを押下し権限設定 (グローバルナビ(スマートフォン用))を表示します。

  • 「権限設定を開始する」ボタンを押下し

  • テストTODOの権限の「参照」権限を認証済みユーザに付与します。

    ../../../../../_images/auth.PNG

    コラム

    • 認可の詳細については 認可 を参照してください。

画面を表示する

作成したプレゼンテーションページをメニューから表示します。

  • クライアントタイプをスマートフォン版へ切り替え、スマートフォン版グローバルナビを表示します。

  • メニューから「テストTODO」を選択すると、先ほど作成されたメニュー「TODO登録」が表示されます。

    スマホ版グローバルナビを表示
  • TODO登録を選択します。目的の画面を表示することができました。

    ../../../../../_images/blank1.PNG

コラム

この項目では、下記のポイントを確認しました。

  • ファイルマッピングに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>
    
  • マークアップ結果。テーマにより最適化されたテキストボックスが表示されました。

    ../../../../../_images/text.PNG

同様に他の要素も配置していきます。

  • 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()
   });
}
  • マークアップ結果。タイトルと日付未入力の状態で登録ボタンを押下すると、
    登録処理が呼出されず入力チェックエラー処理が呼出され、
    エラー画面へ遷移します。
../../../../../_images/validate-error-ssjs.PNG

コラム

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>
    
  • マークアップ結果。タイトルと日付未入力の状態で登録ボタンを押下すると、
    エラーダイアログが表示され警告が出力されます。
    ../../../../../_images/require-error_ja.PNG
    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>
    
  • マークアップ結果。登録ボタン押下後にダイアログが表示され、
    登録処理が正常終了したことが確認できるようになりました。
    ../../../../../_images/ajax-success.PNG

コラム

この項目では、下記のポイントを確認しました。

  • クライアントから非同期でリクエストを送信するには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
    

«  基本的な画面の作り方   ::   コンテンツ   ::   実装例:一覧画面を作る  »