jQuery と Bootstrap をめぐる話題

メニュー

初めに

 ここでは順不同に、jQuery と Bootstrap に関する話題を書いていきます。事の成り行き上、まとまりに欠けることはご了解ください。また、新しい項目に気が付いた場合には、随時内容を増やしまた修正していきたいと思います。

 また以下のファイルを読み込んでいるのが前提です。これ以後の例ではこの記述を省きますので注意してください。また使用しているバージョンは bootstrap 3.3.0 と jQuery 2.1.1 です。この例のままでは動作しない可能性があります。その場合は適宜読み替えてください。

  jQuery と Bootstrap の基礎的な説明はありません。トピック集と位置付けていますので、そうした知識をお持ちとの前提に立っています。

  jQuery 3 が新たにリリースされました。簡単な試験では、ここに書かれている内容そのままで動作を確認してあります。使用しているファイルは jquery-3.1.0.min.js になります。

                     
        <link href="resources/css/bootstrap.min.css" rel="stylesheet" />
        <script src="resources/js/jquery-2.1.1.min.js" type="text/javascript"></script>
        <script src="resources/js/bootstrap.min.js" type="text/javascript"><script>

                 

  jQuery と Bootstrap はブラウザ上の技術です。そのため Web サーバを利用していないこのページでも利用できます。そのため、コードで説明することは必須としても、まずサンプルを提示してその見た目の上で確認できるようにしたいと思います。

form タグの id 属性の使い方

  form タグ内の要素、たとえば input タグにid属性を付けた場合、JSFの仕様として、HTMLに変換される際には input タグの id 属性は「formタグの id の値 : input タグの id の値」となります。つまり「:」で連結されます。

 さらに jQuery は「:」を特別に解釈するため、エスケープして「\\:」とする必要があります。

 区切り文字を変更したい、例えば「:」ではなく「_」にしたい場合は web.xml に次のようにします。

                     
    <context-param>
        <param-name>javax.faces.SEPARATOR_CHAR</param-name>
        <param-value>_</param-value>
    </context-param>    

                 

 ブラウザに依存しないで、ポップアップ形式のモダールダイアログを出したい場合には、 Bootstrap のモダールが便利です。

 下にあるボタンをクリックしてください。ダイアログが表示されます。内容を確認するには、ブラウザに Chrome を使用している場合、右上のメニューから「その他のツール」→「デベロッパーツール」の順に選択して、ソースの HTML を見てください。




  Bootstrap のモダールダイアログのデフォルト動作では、背景の画面が黒の半透明となり、任意の位置でマウスをクリックするとモダール動作を停止します。

ボタンの2重押しの禁止方法

 ボタンの2重押しを禁止する方法は、 Bootstrap のモダールを表示して、サーバから応答があるまですべての処理を禁止することで行っています。 jQuery の部分とモダールの要素を示します。


1   $(function () {
2       $("#mainForm").submit(function() {
3           $("#hideModal").modal();
4           return true;
        });
    });
    
    …
5   <form jsfc="h:form" id="mainForm" class="form-horizontal">
    …
    </form>
6   <div id="hideModal" class="modal" tabindex="-1" role="dialog" data-backdrop="static" data-keyboard="false" >
7       <div class="modal-dialog modal-sm">
8           <div class="modal-content">
9               <div class="modal-body">
10                    <img src="resources/img/ajax-loader.gif" alt="" />
11                      <strong>Loading ...</strong>
                </div>
            </div>
        </div>
    </div>
    …    

                 

 1行目は、 mainForm が submit されたときに、hideModal をモダール動作させています。

 6行目以降は、自由にタグを設計することができます。この例では処理中を意味するアニメーション GIF を表示しています。

  Bootstrap のモダールダイアログの標準の動作は、背景をマウスでクリックするとモダール動作を中断してしまいます。また、 ESC キーを入力した場合もやはり中断します。サーバから応答があるまで中断しないように、data-backdrop="static" と data-keyboard="false" を指定しています。

モダールダイアログの中央寄せの方法




  Bootstrap のモダールダイアログの表示位置は、縦方向で上から三分の二くらいの位置になります。これを画面中にする方法が次になります。1つ上の標準の場合と見比べてください。

                     
1   $(function () {
2       $(".modal").on("show.bs.modal", function() {
3           $(this).css("display", "block");
4           var dialog = $(this).find(".modal-dialog");
5           var offset = ($(window).innerHeight() - dialog.height()) / 2;
6           dialog.css("margin-top", offset);
        });
    });       

                 

 2行目で、$(".modal") としていることから class 属性に .modal を付けていることが前提です。モダール動作の開始時に処理が動作します。

 3行目以降は、ダイアログの大きさとウィンドウの大きさを計算して、中央に移動しています。

モダールダイアログから submit する方法

 次のようなシナリオを想定しています。画面に「削除」ボタンがあり、そのボタンをクリックしたタイミングで、モダールダイアログを表示します。そのダイアログ上の「確認」ボタンをクリックした場合に、 submit することを考えます。

  こちら の画面での削除ボタンは次のようになっています。

                     
1   <div id="confirmModal" class="modal" tabindex="-1" role="dialog" data-backdrop="static" data-keyboard="false" >
2       <div class="modal-dialog">
3           <div class="modal-content">
4               <div class="modal-header">
5                   <h4 class="modal-title" id="myModalLabel">
6                       大分類の削除確認
7                   </h4>
8               </div>
9               <div class="modal-body">
10                  このデータを削除します。よろしいですか?
11              </div>
12              <div class="modal-footer">
13                  <input jsfc="h:commandButton" type="submit" class="btn btn-primary" value="O K" data-dismiss="modal" action="#{majorPageBean.delete()}" />
14                  <input type="button" class="btn btn-primary" value="Cancel" data-dismiss="modal" />
15              </div>
            </div>
        </div>
16      <input id="confirmFlag" type="hidden" value="Cancel" />
    </div>      

                 

 4行目から8行目はダイアログのタイトル部分です。

 9行目から11行目はダイアログの本文部分です。

 12行目から15行目はダイアログのフッター部分で、ここに削除確認のボタンがあります。そのボタンをクリックした場合に delete メソッドが呼び出されます。

table の行をクリックで選択する方法

 見出しを除いて、テーブルの本体の任意の行をクリックしてみてください。行の表示色が変更されます。

場所 産物
北海道 ジャガイモ
沖縄 サトウキビ
佐渡島 トキ

  table タグの1行をクリックした場合に、その行を選択状態に変更する処理です。

                     
1   $(function () {
2       $(".mainRow").click(function(){
3           $(".mainRow").removeClass("info");
4           $(this).addClass("info");
5           $("#mainForm\\:selectedId").val($(this).children(".majorId")[0].innerText);
        });
    });
    
6   <table id="majorView" class="table table-condensed table-bordered p100">
        <thead>
            <tr>
                <th class="p5 text-center">ID</th>
                <th class="p20 text-center">名称</th>
                <th class="p20 text-center">コメント</th>
            </tr>
        </thead>
        <tbody>
7           <tr jsfc="ui:repeat" var="major" value="#{majorPageBean.majors}" class="mainRow">
                <td class="majorId text-left">#{major.id}</td>
                <td class="text-left">#{major.name}</td>
                <td class="text-left">#{major.comment}</td>
            </tr>            
        </tbody>
    </table>
8   <input jsfc="h:inputHidden" id="selectedId" type="hidden" value="#{majorPageBean.selectedId}" />

                 

 6行目で使用している table table-condensed table-bordered は Bootstrap で定義してあります。

 7行目が重要で、テーブルの行に対して class 属性に mainRow を指定しています。

 8行目は、現在選択中の値を格納するための hidden 要素です。 jQuery で設定し、管理 Bean でその値を読み取って処理を行います。

 2行目は、class 属性が mainRow である要素がクリックされたときに処理されます。

 3行目で、すべての行の色をデフォルトに戻しています。 info は Bootstrap で定義されている色です。

 4行目で、現在クリックされた行の色を選択色に設定しています。

 8行目で、hidden 要素に選択行の ID を格納しています。この値はデータをユニークに識別できる必要がありますので、アプリケーション毎に調整してください。

 上記例に p5 や p20 といった記述があります。これは個人が管理している CSS の内容です。無視してかまいません。表示幅をパーセントで指定するものになります。

ブラウザで必須項目の検査をする方法

 以下のテキストボックスに何かメッセージを入力して、「確定」ボタンをクリックしてみてください。

メッセージ

                     
1   $(function () {
2       $("#mainForm\\:addButton").click(function () {
3           $("#errorMessage").text("");
4           var msg = "";
5           if ($("#mainForm\\:inputId").isNull()) {
6               msg += makeMessage("IDは必須項目です。");
            }
7           if (msg.length === 0) {
8               return true;
            }
9           else {
10              $("#errorMessage").append(msg);
11              return false;
            }
        });
    });               

                 

  HTML には「追加」ボタンが存在し、その id 属性は addButton であることと、エラー表示用のタグが存在し、その id 属性は errorMessage であることが前提です。

 2行目で、追加ボタンがクリックされたときに処理が起動します。

 3行目でエラー内容を初期化します。

 5行目で空文字列かどうかの検査を行っています。 isNull は私が個人で使用している jQuery のライブラリです。

 6行目で文字列を書式に合うように編集しています。このサンプルでは、エラー表示は <ul><li></li</ul> タグを使用することを前提としているためです。利用の都合に合わせてください。

 8行目で、正しい条件であったため true を返しています。 true を返すと、サーバに対して submit されます。

 11行目ではエラーがあったため false を返します。この場合はサーバには submit されません。

jQuery から使用できるライブラリ

 個人で使用している jQuery 用のライブラリを次に示します。もともとは javascript 用でしたが、 jQuery 用に書き換えたものです。コメントが多量に付けてありますので、理解は容易と思います。

                     
(function ($) {
    /*
    入力がなにもないかどうかを検査する
    空白コードが存在しても,入力があったと判断する
      
    戻り値:
    入力がない場合にtrue,そうでない場合にfalse
    */
    $.fn.isNull = function () {
        return (this.val().length == 0);
    };

    /*
    引数で指定した文字数が入力されているかどうかを検査する
       
    引数:
    min 最少文字数
    max 最大文字数
      
    戻り値:
    必要な文字数が入力されている場合にtrue,そうでない場合にfalse
    */
    $.fn.isValidLength = function (min, max) {
        var len = this.val().length;
        return (len >= min && len <= max);
    };

    /*
    数字キー(0-9)以外のキーが入力されていないかどうかを検査する
    入力がない場合も真と判断するため,必須項目の場合は,isNull()と併用すること
       
    戻り値:
    数字キーだけまたは空文字列の場合にtrue,そうでない場合にfalse
    */
    $.fn.isNumber = function () {
        var value = this.val();
        if (value.length == 0)
            return true;

        return !(value.match(/^\d+$/));
    };

    /*
    英文字以外のキーが入力されていないかどうかを検査する
    入力がない場合も真と判断するため,必須項目の場合は,isNull()と併用すること

    戻り値:
    英文字だけまたは空文字列の場合にtrue,そうでない場合にfalse
    */
    $.fn.isAlpha = function () {
        var value = this.val();
        if (value.length == 0)
            return true;

        return !(value.match(/[^a-zA-Z]/));
    };

    /*
    英数文字以外のキーが入力されていないかどうかを検査する
    入力がない場合も真と判断するため,必須項目の場合は,isNull()と併用すること

    戻り値:
    英数文字だけまたは空文字列の場合にtrue,そうでない場合にfalse
    */
    $.fn.isAlphaNumber = function () {
        var value = this.val();
        if (value.length == 0)
            return true;

        return !(value.match(/[^0-9a-zA-Z]/));
    };

    /*
    0以上の整数かどうかを検査する
    05は整数ではないのでfalseとなる
    入力がない場合も真と判断するため,必須項目の場合は,isNull()と併用すること
       
    戻り値:
    0以上の整数の場合にtrue,そうでない場合にfalse
    */
    $.fn.isPositiveNumber = function () {
        var value = this.val();
        if (value.length == 0)
            return true;

        if (!value.match(/^\d+$/))
            return false;

        if (value.length <= 1)
            return true;

        return (value.charAt(0) != "0");
    };


    /*
    整数かどうかを検査する
    05は整数ではないのでfalseとなる
    入力がない場合も真と判断するため,必須項目の場合は,isNull()と併用すること
       
    戻り値:
    整数の場合にtrue,そうでない場合にfalse
    */
    $.fn.isNumber = function () {
        var value = this.val();
        if (value.length == 0)
            return true;

        if (!value.match(/^[-]?[0-9]+(\.[0-9]+)?$/))
            return false;

        if (value.length <= 1)
            return true;

        return (value.charAt(0) != "0");
    }
    /*
    正しい日付と判断できるかどうかを検査する
    有効な書式は,区切り文字に「-」または「/」を使用した場合,または
    年4桁・月2桁・日2桁の8桁の数字を使用し,
    日付として有効な組み合わせであること
       
    例:
    2014/1/1
    2014/1-1
    20140228
      
    戻り値:
    有効な日付の場合にtrue,そうでない場合にfalse	
    */
    $.fn.isDate = function () {
        return this.getDate() != null;
    };

    /*
    日付に対応するDate型のオブジェクトを返す
    有効な日付の書式は,isDate()のコメントを参照せよ
       
    戻り値:
    有効な日付の場合にDate型のオブジェクトを,そうでない場合null
    */
    $.fn.getDate = function () {
        var value = this.val();
        if (value.length == 0)
            return null;

        var a = new Array();
        var date = value.replace("-", "/");
        if (date.match(/^\d{2,4}\/\d{1,2}\/\d{1,2}$/))
            a = date.split("/");
        else if (date.match(/^\d\d\d\d\d\d\d\d$/)) {
            a[0] = date.substring(0, 4);
            a[1] = date.substring(4, 6);
            a[2] = date.substring(6, 8);
        }
        else
            return null;

        var nd = new Date(a[0], a[1] - 1, a[2]);
        if (a[0] == nd.getFullYear() && a[1] == nd.getMonth() + 1 && a[2] == nd.getDate())
            return nd;

        return null;
    };
})(jQuery);

                 

ファイルアップロードのボタンを Bootstrap に合わせる方法

 ボタンの class 属性に、 Bootstrap の値 btn btn-primary を設定すると、以下のようになります。



 次に、ファイルアップロード用の input タグは以下のようになります。


 ファイル選択のボタンの表示はブラウザに任されています。そのため両方の見た目をそろえるためには、工夫が必要です。
 下にある「ファイルを選択」ボタンをクリックし、ダイアログからファイルを選択してみてください。


 これを実現する工夫は、ファイルアップデート用の input タグを hidden で隠します。それとは別にボタンとラベルからなるコントロールを表示しておきます。そしてそのボタンをクリックした場合に、隠してある input タグを起動するというものです。

                     
1   $(function () {
2       $("#hiddenName").on("change", changeFunc);                        

3       function changeFunc(eo) {
4           var txt = $("#hiddenName").val();
5           var index = txt.lastIndexOf("\\");
6           if (index >= 0)
7               index += 1;
            else
8               index = 0;
9           txt = txt.substr(index);
10          if (txt.length == 0)
11              txt = "選択されていません";
                        
12          $("#fileName").text(txt);
        }
    });
    
13  <input id="hiddenName" type="file" class="hidden" />
14  <div class="input-append">
15      <button class="btn btn-primary" type="button" onclick="$('#hiddenName').click();">ファイルを選択</button>
16      <label id="fileName">選択されていません</label>
    </div>

                 

 13行目は、hidden 要素である input タグになります。

 15行目は、ファイル選択用のボタンです。 onclick="$('#hiddenName').click();" からボタンクリック時に隠し要素の input タグを起動します。

 16行目は、選択されたファイル名を表示するためのラベルになります。

 2行目は、隠し要素の input タグの値が変更した場合に呼び出されます。

 4行目から11行目で、選択されているファイル名を加工しています。この部分は Windows 上の Chrome で動作確認してあります。別の OS やブラウザの場合に処理手順を変える必要があるかも知れません。特に、5行目は添付ファイルの絶対パス名からファイルのベース名を切り出すことに関係しています。

 12行目で、ラベルにファイル名を表示しています。