業務アプリ開発講座

モーダルウィンドウ・スタッフ追加

スタッフ一覧には2つの機能がモーダルウィンドウを開きます。一覧右上の追加ボタンと氏名列です。
モーダルウィンドウ関連のプログラミング1から組み上げようとするとなかなか大変ですので、JQueryとBootstrapの派生APIを幾つか利用しながら実装しようと思います。

以下をダウンロードし、asstes/js内にコピーします。staff-list.phpにこれらを読み込むように<script>タグを追加しておきます。

<script src="../assets/js/bootstrap-confirmation.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../assets/js/jquery.validate.js" type="text/javascript" charset="utf-8"></script>

bootstra-confirmation

stock-1

ボタンをクリックした際のConfirmダイアログを表示します。Javascriptにもconfirm()機能はありますが、ここではより見栄えが良い、Bootstrap-confirmationを利用します。

jquery.validate

stock-1

入力チェックJavascriptAPIです。簡単に入力チェックを設定できますし、カスタマイズでかなり凝ったチェックを作りこむこともです。後々、サーバーの入力チェックとクライアントの入力チェックを同じ設定ファイルを使用するように作りますが、まずは、利用価値の高いJQuery.Validateを使います。

続いて、スタッフ新規追加モーダルウィンドウHTMLと既存スタッフの編集モーダルウィンドウHTMLをナビゲーションの時と同じように外部ファイル化します。といっても必ずしも外部ファイル化する必要はありません。
staff-list.phpに直書きしても同じです。外部ファイル化の効用はモーダルウィンドウ内の初期化が楽にできますので、状態に応じて要素を表示非表示を切り替えたり、元に戻したりの処理コードを減らすことができます。わずかですがシンプルなソースにできます。

例えば、以下の手順で画面を操作してみましょう。

  1. 「追加」ボタンをクリックして、新規追加モーダルウィンドウを開きます。
  2. 何も入力せずに「登録」ボタンをクリックします。すると各入力フォーム下に警告メッセージが表示されます。
  3. その状態で、グレー背景か右上のををクリックして、モーダルウィンドウを閉じます。
  4. 再度「追加」ボタンをクリックしてモーダルウィンドウを開きます。

するとどうでしょう、先ほどの警告メッセージが表示されたままの状態で、モーダルウィンドウが開かれます。「追加」ボタンをクリックした際は、初期状態で表示されてほしいものです。この初期状態戻す処理を簡単にする方法として、都度外部HTMLを読み込むわけです。

グレー背景か右上のををクリックした際に、警告メッセージを消すという処理を入れても同じことですが、「追加」ボタンクリックイコール初期化ですので、ここでは外部ファイルを再読み込む方法をとります。使用によっては外部ファイル化しない方が簡単な場合も当然あります。ですので、どちらがいいというわけではなく、あくまで幾つかある方法論の内の一つであるという認識が大切です。

<div class="modal-dialog">
	<div class="modal-content">
		<form id="AddForm" class="form-horizontal">
			<div class="modal-header">
				<button type="button" class="close" data-dismiss="modal">×</button>
				<h4 class="modal-title">スタッフを追加します。</h4>
			</div>
			<div class="modal-body">
				<div class="row">
					<div class="col-md-1"> </div>
					<div class="col-md-10">
	
	<div class="form-group">
		<label class="col-md-5 control-label">ID</label>
		<div class="col-md-7">
			<label id="StaffId" class="control-label optional"></label>
		</div>
	</div>
	<div class="form-group">
		<label class="col-md-5 control-label">氏名</label>
		<div class="col-md-7">
			<input id="StaffName" name="StaffName" type="text" class="form-control required">
		</div>
	</div>
	<div class="form-group">
		<label class="col-md-5 control-label">メールアドレス</label>
		<div class="col-md-7">
			<input id="StaffMail" name="StaffMail" type="text" class="form-control email required">
		</div>
	</div>
	<div class="form-group">
		<label class="col-md-5 control-label">スタッフ区分</label>
		<div class="col-md-7">
			<select id="StaffType" name="StaffType" class="form-control required">
				<option value=""></option>
				<option value="0">社員</option>
				<option value="1">アルバイト</option>
			</select>
		</div>
	</div>
	<div class="form-group">
		<label class="col-md-5 control-label">管理区分</label>
		<div class="col-md-7">
			<select id="JobType" name="JobType" class="form-control required">
				<option value=""></option>
				<option value="0">管理者</option>
				<option value="1">管理補佐</option>
				<option value="2">レジ</option>
			</select>
		</div>
	</div>
	<div class="form-group">
		<label class="col-md-5 control-label">採用日</label>
		<div class="col-md-7">
			<input id="HireDate" name="HireDate" type="date" class="form-control date required">
		</div>
	</div>

					</div>
					<div class="col-md-1"> </div>
				</div>
			</div>
			<div class="modal-footer">
				<div class="row">

	<div class='col-xs-6 btn-card-block text-left'>
		<a href="../assets/images/staff-card/2458888137476.png" target="_blank" class="btn btn-warning btn-ok">スタッフカード</a>
	</div>
	<div class='col-xs-6 text-right'>
		<div class='btn-group btn-add-block'>
			<a href="#" class="btn btn-default" data-dismiss="modal">閉じる</a>
			<a href="#" class="btn btn-primary btn-add">登録</a>
		</div>
	</div>

				</div>
			</div>
		</form>
	</div>
</div>

追加ボタンをクリックすると、このHTMLを読み込んで、staff-list.phpの所定のタグに当てはめます。

表示イメージです。この段階のソースではまだ表示出来ませんが、このように表示されるようになります。

stock-1

このモーダルウィンドウの機能

「登録」ボタン
クリックすると登録処理の際に新たに発行するIDをID枠に挿入し、同時に生成されたスタッフカード画像へのLinkボタンを表示します。
「閉じる」、右上✖︎、グレー背景
モーダルウィンドウを閉じます。

「登録」ボタンをクリック後の画面イメージです。


stock-1

「スタッフカード」ボタン
追加登録したスタッフにスタッフカードを渡さなければなりません。登録処理をしたらすぐにスタッフカードを印刷できるように、この段階でスタッフカード画像を表示できるようにします。スタッフカードボタンをクリックで、画像を別窓表示します。

入力チェック機能はモーダルウィンドウの表示機能を実装した次に解説します。

次に、staff-list.phpに戻って、modal-add.htmlを当てはめるタグを追記します。一覧Tableの直下に追記します。

<!-- Add Staff Modal Window -->
<div class="staff-modal-add modal fade"></div>
<!-- /Add Staff Modal Window -->

さらに、「追加」ボタンのタグを下記の通り変更します。

<a href="#" class="btn btn-primary btn-modal-add">追加</a>

class属性にbtn_modal-addを追加し、ボタンを識別できるようにします。

これで、下準備はできました。次は「追加」ボタンのクリックイベントでモーダルウィンドウが表示されるようにJavascriptソースを書き加えます。

<script type="text/javascript">
$(function(){
	//一覧の生成
	bindGrid();

	//追加ボタンをクリック
	$(".btn-modal-add").on("click", function(){
		openAddModal();
		return false;
	});
	//追加登録モーダルウィンドウが閉じられたら、外部ファイル分のタグを削除します。
	$(".staff-modal-add").on('hidden.bs.modal', function(){
		$(this).children().remove();
	});
});

//追加登録モーダルウィンドウを開く
function openAddModal(){
var	modalWin	= $(".staff-modal-add");
	modalWin.load("../assets/template/staff/modal-add.html");
	modalWin.modal('show');
	$("#AddForm").validate();
	$('a.btn-add').on('click', function(){
		addStaff();
		return false;
	});
	appendFormCaption();
}

//スタッフ追加登録時の処理
function addStaff(){
	var form, modalTitle;

	form	= $("#AddForm");
	if(!form.valid())	return;

	modalTitle	= $(".staff-modal-add .modal-title");
	modalTitle.text($("#AddForm #StaffName").val() + "さんを追加しました。");
	modalTitle.css("color", "#00D");
	$(".btn-add").attr({"disabled", "disabled"});
	$(".btn-card-block a").css({"display":"inline-block"});

	$("#StaffId",	form).text("845264857592");
}

//入力フォームの[必須]キャプションの追加
function appendFormCaption(){
	$('.required').parent().prev().append(formCation.required);
	$('.optional').parent().prev().append(optional);
}
</script>

Javascriptソースの解説

$(".btn-modal-add").on("click", function(){});

.btn-modal-addは「追加」ボタンの識別classですね。この命令は「追加」ボタンにクリックイベントを登録するという意味です。onは第1引数のイベントを登録し、実行された場合に、第2引数のfunction()内のコードを実行します。この場合は関数openAddModal()を呼んでいます。次の行のreturn falseを追記することで、以前出てきましたonclick="func(); return false"と同じ意味になり、<a>の遷移イベントを無効にしています。

$(".staff-modal-add").on('hidden.bs.modal', function(){});

.staff-modal-addはモーダルウィンドウの本体を指していますね。この命令は、「モーダルウィンドウが閉じられたら」というイベントを登録しています。hidden.bs.modalBootstrap.jsに用意されている「モーダルウィンドウが閉じられた」というイベント名です。そしてイベントが実行された場合の処理は、.staff-modal-addの子要素を全て削除します。こうすることで、次、「追加」ボタンをクリックした際に、再度外部ソースを読み込みますので、モーダルウィンドウを初期化できるわけです。

呼び出されたfunction openAddModal()はスタッフ追加用モーダルウィンドウを開き、その中のボタンに先ほどと同じようにイベント登録しています。

var modalWin = $(".staff-modal-add");

.staff-modal.addオブジェクト(モダールウィンドウのHTML部分)を変数に格納しています。ここで、Jqueryの一つの特徴として、セレクタ$()あるいはjQuery()は、DOM(Document Object Model)、つまりHTMLを解析して生成されたオブジェクトを全て検索しに行きます。

例えば

$(".staff-modal-add").load("../assets/template/staff/modal-add.html");
$(".staff-modal-add").modal('show');

と記述することでできますが、この書き方をすると.staff-modal.addを全てのDOMへ2回検索することになるわけです。同じオブジェクトを示すのに、都度最初から検索し直させるのも無駄ですね。ですので、変数に指定のオブジェクトを格納し再利用するわけです。

もう一つのセレクタの書き方で$("セレクタ", オブジェクト)という書き方があります。このように書くとオブジェクト名に対し、セレクタを検索するという意味になります。後でこの書き方が出てきます。

modalWin.load("../assets/template/staff/modal-add.html");

これはajaxを使った外部HTMLを読み込み指定のセレクタに当てはめる、シンプルな記述命令です。load以外にもpostgetJSONなど複数の簡易ajaxが用意されています。
ここでは、.staff-modal.addに、指定URLの外部HTMLを当てはめるという意味になります。

modalWin.modal('show');

これはモーダルウィンドウを表示するという命令で、Bootstrap.jsに用意されています。.modal()に引数にhideを指定するとモーダルウィンドウを閉じる命令になります。

$("#AddForm").validate();

jquery.validateの機能を有効にしてます。ここで、有効にすることで、例えばメールアドレスに無効な文字を入力した際、すぐに警告文を画面に表示されるようになります。

警告文の表示イメージです。

stock-1

$('a.btn-add').on('click', function(){
    addStaff();
    return false;
});

モーダルウィンドウ内の「登録」ボタンにクリックイベントを登録します。addStaff()関数を呼び出しています。return falseは上記と同じ意味です。

なぜ、最初の$(function()({})部分ではなく、ここでイベントを登録するかというと、一覧の初期画面ではまだモーダルウィンドウのソースは読み込まれていません。つまり、「登録」ボタンは、その時点では存在しないのです。存在しないオブジェクトにイベントを登録しようとしても、無意味な処理になってしまいます。外部HTMLが読み込まれてDOMに登録されてはじめて存在し、イベントを登録することができようになるのです。ですので、ここで登録処理をしているわけです。

appendFormCaption();

フォームの各項目右にある[必須]キャプションを付加する関数を読んでいます。
addStaff()関数を解説する前に、appendFormCaption()を解説しましょう。さらにその前に、下記ソースを前回作成したconfig.jsに追記します。

var forCaption = {
    required : '<span class="caption-required">[必須]</span>',
    optional : '<span class="caption-optional"> </span>'
}

では、ソースの解説です。

$('.required').parent().prev().append(formCaption.required);

moda.add.htmlのソースを見てみましょう。各入力フォームのclass属性にrequiredがあります。その入力フォームの親オブジェックト(parent())、つまり<div>の前のオブジェクト(prev())、つまり<label>formCaption.required、つまり<span class="caption-required">[必須]<apan>を当てはめています。

$('.optional').parent().prev().append(optional);

同じように、optionalを当てはめています。

caption-requiredcaption-optionalのスタイルです。bookmin.cssに追記しておいきます。

span.caption-required{
	font-size:8pt;
	font-weight:normal;
	color:#B00;
	margin-left:12px;
}
span.caption-optional{
	font-size:8pt;
	font-weight:normal;
	color:#FFF;
	margin-left:36px;
}

最後、addStaff()です。

var form, modalTitle;
form = $("#AddForm");

ここは良いでしょう。変数の宣言と、formオブジェクトを変数formに代入しています。

if(!form.valid())	return;

これは、フォームの入力値が有効でなかったら、処理を中断するという意味です。もし、実入力や不正入力があった場合、各フォーム下に警告メッセージが表示されます。

入力チェックはWebシステムにおいて必ず実装なければならないものです。SQLインジェクションやXSSなどセキュリティ上の脅威を排除するためにとても重要なことです。入力チェックはサーバー側(PHPやJava等)とクライアント側(Javascript等)の両方で実装します。そして絶対に実装しておいておかなければなならないのがサーバー側の入力チェクです。クライアント側で実装しているから必要なんじゃないかというとそういうわけにはいかないのです。サーバーに送信するデータが必ずブラウザ上で人が入力しているとは限りません。HTTPは非常にシンプルな仕様なので、簡単にブラウザを偽装したり、独自のプログラムを使って自動で不正データを送信することも簡単にできてしまうんですね。もう少しこの講座を進めるとあなたにも簡単にできるようになります。逆にサーバーで実装するならクライアント側は必要ないんじゃなかいというと、やっぱり実装しておいたほうが良いのです。サーバー側で無駄な処理を減らすことができるからです。Webアプリの通常の利用において、未入力やちょっとした入力ミスなどは付き物です。クライアント側で是正できるものは直してから送信してもらえれば、それだけサーバーの負担を減らすことができます。

さて、このステップでは、クライアント言語()HTML, CSS, Javascript)のみで画面を作っています。以下は、サーバー側で登録処理を行った結果を踏まえての処理になるのですが、また、サーバープログラミングを実装していませんので、登録処理がうまくいった場合のみを実装しています。

modalTitle	= $(".staff-modal-add .modal-title");
modalTitle.text($("#AddForm #StaffName").val() + "さんを追加しました。");
modalTitle.css("color", "#00D");

モーダルウィンドウのタイトルを変更しています。「スタッフを追加します」から「(入力した氏名)さんを追加しました」に、また、タイトルの文字色を青に変えています。このように表示を変えることで登録処理が無事に行えたことを通知しています。

$(".btn-add").attr({"disabled":"disabled"});

「登録」ボタンを無効にしています。これは同じデータを2重送信できなくするためです。
「登録」ボタンをまず無効にし、サーバー処理の結果が成功だった場合はそのままに、失敗だった場合には、再度有効に戻すと良いでしょう。
有効に戻すには$(".btn-add").removeAttr("disabled")とするか$(".btn-add").removeAttr({"disabled":false})とします。

.attr().css()など、同じオブジェクトに対し、複数の要素を設定したい場合があります。例えば、上記のモーダルウィンドウのタイトルのスタイルを、文字色を青にし、太字にし、アンダーラインを引くとします。その際の書き方には、以下の3種類があります。

#1
modalTitle.css("color", "#00D");
modalTitle.css("font-weight", "bold");
modalTitle.css("text-decoration", "underline");
#2
modalTitle.css({	"color"		:"#00D",
			"font-weight"	:"bold",
			"text-decoration":"underline"});
#3
.title-success{
	color:#00D;
	font-weight:bold;
	text-decoration:underline;
}
modalTitle.addClass("title-success");

#1はスタイルを一つ一つ設定していく書き方で、#2は複数のスタイルをJSON形式まとめて1度に設定する書き方です。#1は設定の度に画面を再描画しますので、非効率的です。複数の要素を指定する場合は、#2あるいは#3のようになるべく一度に設定するようにしましょう。#3はソースもすっきりし、名前からどうしたいのかがはっきり伝わりますので、よりオススメです。

$(".btn-card-block a").css({"display":"inline-block"});

「スタッフカード」ボタンを表示します。

$("#StaffId",	form).text("845264857592");

新規登録モーダルウィンドウですので、追加登録に成功した際には、登録スタッフに新しいIDが発行されます。そのIDをサーバー処理の戻りとして受け取り、画面に表示します。