Ajax をシンプルに利用できるライブラリ

フレームワークプログラミング

Ajax を簡単でシンプルに利用できるようなライブラリを作成しましたので紹介します。
以下のような機能があります。

・フォームの送信
・ファイルアップロード(multipart/form-data)にも対応
・送信データの直接指定
・リクエストヘッダーの設定
・ローダー表示による2重 POST 防止
・応答受信後の処理(メッセージ出力、リロードなど)をサーバ側(応答側)から指定
・応答受信後の HTML の更新やフォーム値の変更をサーバ側(応答側)から指定
・送信時の前処理・後処理の実装
・JSONP による強制クロスサイトアクセス

GitHub
https://github.com/yanox2/pronto/

機能を確認できるデモ画面を作りました。

デモ画面を開く


ローダー
サーバとの通信中などに使用できるローダーです。
ローディング中は画面の操作が無効になり、2重ポストを防ぎます。

PRLoaderクラスをnewして使用します。
enable()メソッドがロード開始でdisable()メソッドがロード終了です。
サンプルでは submit ボタンを押すとローディング中となり、5秒経過した後にメッセージを表示して復帰します。

$("#id_submit").on("click", function(){
	var lod = new PRLoader();
	lod.enable(); // ロード開始
	setTimeout(function(){
		lod.disable(); // ロード終了
		alert("ロードが完了しました。");
	}, 5000);
});

bodyタグ直下に以下のタグを記述します。
<div class="loader"></div>の部分を別のローダーに置き換えることで、様々なローダーを実装することができます。

<body>
<div id="prTag_maskAll" class="prSt_maskAll"></div>
<div id="prTag_loader" class="prSt_loader">
 <div class="loader"></div>
</div>
・・・

サンプルでは以下のスピナーを使用させていただいております。
参考: Single Element CSS Spinners (MIT License)


フォームの POST
PRAjaxクラスは Ajax 通信を支援するクラスです。
onSubmit()メソッドは指定されたフォームの submit を検知し、フォームデータを Ajax で送信します。
フォームタグの attribute を読み取って通信先や通信種別(GET/POST)を自動的に決定します。
通信中はローダーが作動し、2重ポストを防ぎます。

PRAjaxクラスをnewして使用します。
onSubmit()メソッドにフォームの ID を渡します。

var ajax = new PRAjax();
ajax.onSubmit("#id_form1");

ファイルのアップロード(enctype="Mutipart/form-data")にも対応しています。
PRAjaxの使い方は変わりません。

<form id="id_form1" name="name_form1" enctype="multipart/form-data" method="post" action="response.php">


送信データの指定
PRAjaxクラスに送信データを直接指定して通信ができます。
送信データは JSON 形式で指定します。
まず送信先 URL および通信種別(GET/POST)を指定してPRAjaxnewします。
setData()メソッドに送信データを設定し、send()メソッドで送信します。

$("#id_btnGET").on("click", function(){
	var ajax = new PRAjax("response.php", "get");
	var data = {
		"name_inputText1": "テキストボックス1",
		"name_textArea1": "テキストエリア1",
		"name_radio": "ラジオ",
		"name_checkbox1": "チェックボックス1",
		"name_select1": "セレクト1"
	};
	ajax.setData(data);
	ajax.send();
});

onClick()メソッドを使用すればいちいち JQuery の on メソッドを記述せずにすみ、全体のコード量を減らすことができます。
onClick()メソッドにクリックに対応するタグの ID および送信するデータを指定します。
第3引数をtrueとした場合は、指定された ID の:hover(マウスオーバー)がクリッカブルになります。

var getAjax = new PRAjax("response.php", "get");
getAjax.onClick("#id_list1", {"no":1}, true);
getAjax.onClick("#id_list2", {"no":2}, true);
getAjax.onClick("#id_list3", {"no":3}, true);
getAjax.onClick("#id_list4", {"no":4}, true);
getAjax.onClick("#id_list5", {"no":5}, true);

タグの ID がボタンである必要はありません。

・・・
<tr id="id_list1">
 <th scope="row">1
 <td>James
 <td>Smith
 <td>@james
 <td><i id="id_icon1" class="bi bi-pencil">
</td>
・・・

また、setHeaders()メソッドでリクエストヘッダに値を設定できます。

var getAjax = new PRAjax("response.php", "get");
getAjax.setHeaders({"abc":"def"});
getAjax.onClick("#id_list1", {"no":1}, true);


送信後の自動処理
レスポンスデータに命令ワードを設定することにより、送信後(応答受信後)に所定の処理を行います。

・メッセージ出力
"message"に出力するメッセージ文を指定すると、送信後にalert()でメッセージを出力します。

・確認メッセージ
"confirm"にメッセージ文を指定すると、送信後にconfirm()で確認メッセージを出力します。
ユーザの選択結果は後述の後処理に渡されます。

・ページ移動
"location"に移動先 URL を指定すると、送信後にlocation.href()でページを移動します。

・リロード
"reload"trueを指定すると、送信後にページのリロードを行います。

$res = array();

// メッセージ出力
$res['message'] = $_REQUEST['name_textArea1'];

// 確認メッセージ
$res['confirm'] = $_REQUEST['name_textArea1'];

// ページ移動
$res['location'] = 'index2.php';

// リロード
$res['reload'] = true;

$response = json_encode($res, JSON_UNESCAPED_UNICODE);
print $response;


送信後の自動処理(HTMLやフォーム値の変更)
レスポンスデータに"dom"を設定することにより、送信後(応答受信後)に HTML の DOM 操作を行います。
レスポンスデータ$res['dom']['XXXX']XXXXに以下の命令セットのいずれかを指定し、変更を行う要素の ID と値を配列で指定します。

・append
ID で指定された要素の中の最後尾にタグが追加されます。

・prepend
ID で指定された要素の中の先頭にタグが追加されます。

・after
ID で指定された要素の直下にタグが追加されます。

・before
ID で指定された要素の直前にタグが追加されます。

・replace
ID で指定された要素の中身、あるいはvalueを上書きします。

・removef
ID で指定された要素を削除します。

$dom = array();

$dom['append'] = array('id_area1'=>'<div id="id_append" class="ele">append</div>');
$dom['prepend'] = array('id_area1'=>'<div id="id_prepend" class="ele">prepend</div>');
$dom['after'] = array('id_area1'=>'<div id="id_after" class="ele">after</div>');
$dom['before'] = array('id_area1'=>'<div id="id_before" class="ele">before</div>');
$dom['replace'] = array('id_source'=>'replace');

$res = array();
$res['dom'] = $dom;
$response = json_encode($res, JSON_UNESCAPED_UNICODE);
print $response;

レスポンスデータ$res['dom']['replace']は、送信後(応答受信後)にフォーム内にあるINPUTタグなどのvalueの値を変更することもできます。
これは例えばフォームを搭載したモーダルウィンドウの使いまわしなどで利用されます。

$reps = array();
$reps = array(
	'id_inputText1'=>'値1',
	'id_textArea1'=>'値2',
	'name_radio'=>'val_radio3',
	'id_checkbox1'=>'val_checkbox1',
	'id_checkbox2'=>'',
	'id_checkbox3'=>'val_checkbox3',
	'id_select1'=>'val_option3'
);

$res = array();
$res['dom']['replace'] = $reps;
$response = json_encode($res, JSON_UNESCAPED_UNICODE);
print $response;


前処理・後処理
Ajax 通信時の前処理・後処理を実装できます。
PRAjaxクラスを継承し、before()メソッドをオーバーライドして前処理を、after()メソッドをオーバーライドして後処理を記述します。
before()メソッドへの引数は、onSubmit()メソッドの第2引数、onClick()メソッドの第4引数、send()メソッドの第2引数で指定します。
return falseすることで Ajax 送信を中止することができます。

サンプルでは入力チェックが NG の場合にエラーメッセージを出力して送信が中止されます。
また引数を元に確認メッセージを出力し、「キャンセル」であれば送信を中止します。

after()メソッドの引数dataからレスポンスデータを取得することができます。
サンプルではレスポンスデータ全体の文字列や、一部の要素の値を出力しています。
また第4引数はサーバ側から命令ワード"confirm"が使用された場合の選択結果が設定されます。

class MyAjax extends PRAjax{
	before(args){
		var msg = "";
		if(!$("#id_inputText1").val()) msg = msg + "inputText1を入力してください。\n";
		if(msg){
			alert(msg);
			return false;
		}
		var confirm = window.confirm(args);
		if(!confirm) return false;
	}

	after(data, textStatus, jqXHR, confirm){
		alert(JSON.stringify(data.vals));
		alert(data.vals.radio);
	}
}

var ajax = new MyAjax();
ajax.onSubmit("#id_form1", "入力された内容で送信します。よろしいですか?");

コールバックメソッドを設定することでも前処理・後処理を実装できます。
継承が面倒という方はこちらを使いましょう。
それぞれsetBefore()メソッド、setAfter()メソッドでコールバックを設定します。

var ajax = new PRAjax();
ajax.setBefore(function(args){
	var msg = "";
	if(!$("#id_inputText1").val()) msg = msg + "inputText1を入力してください。\n";
	if(!$("#id_textArea1").val()) msg = msg + "textArea1を入力してください。\n";
	if(!$("#id_select1").val()) msg = msg + "select1を選択してください。\n";
	if(msg){
		alert(msg);
		return false;
	}
	var confirm = window.confirm(args);
	if(!confirm) return false;
});
ajax.setAfter(function(data, textStatus, jqXHR, confirm){
	alert(JSON.stringify(data.vals));
	alert(data.vals.radio);
});
ajax.onSubmit("#id_form1", "入力された内容で送信します。よろしいですか?");


クロスサイトアクセス(JSONP)
クロスサイト(外部サイト、外部サーバ)への通信は、受信側がそれを許可している場合にのみ有効です。
具体的には、レスポンスヘッダAccess-Control-Allow-Originに許可するアクセス元が設定され、それに合致する必要があります。

サンプルでは応答を返すresponse.phpでアクセス元https://xxxx.comを許可するようヘッダを設定しています。
Access-Control-Allow-Originにはワイルドカードも設定可能です。

$vals = array();
$vals['inputText1'] = $_REQUEST['name_inputText1'];
$vals['textArea1'] = $_REQUEST['name_textArea1'];

header('Access-Control-Allow-Origin: https://xxxx.com');
//header('Access-Control-Allow-Origin: *');

$res = array();
$res['vals'] = $vals;
$response = json_encode($res, JSON_UNESCAPED_UNICODE);
print $response;

JSONP【JSON with Padding】のデータタイプを利用することにより、CORS Policy 違反を回避することができます。
PRAjaxコンストラクタの第3引数にtrueを指定することで JSONP の Ajax 通信となります。
なお、JSONP はその仕組み上GETしかできないため、POSTを指定してもGETで送信されます。
※JSONP による通信はセキュリティ的な問題をはらんでいますのでご注意ください(JSONP インジェクション)。

// get (JSONP)
var getAjax2 = new PRAjax(url, "get", true);
getAjax2.onClick("#id_btnGET", data);

// post (JSONP)
var postAjax = new PRAjax(url, "post", true);
postAjax.onClick("#id_btnPOST", data);


クロスサイトの Preflight
例えばリクエストヘッダを追加するなどの特殊なクロスサイトアクセスでは、プリフライト【Preflight】リクエストが発生します。
この場合、まずOPTIONSで許可があるかどうか事前に確認し、その後に実際のリクエストが送信されます。
受信側はOPTIONSを受け取る可能性があることを考慮して実装します。

プリフライトリクエスト
$method = $_SERVER['REQUEST_METHOD'];
if($method == 'OPTIONS'){
	header('Access-Control-Allow-Origin: https://xxxx.com');
	header('Access-Control-Allow-Headers: abc');
	//header('Access-Control-Allow-Headers: *');
	exit();
}

$vals = array();
$vals['inputText1'] = $_REQUEST['name_inputText1'];
$vals['textArea1'] = $_REQUEST['name_textArea1'];

header('Access-Control-Allow-Origin: https://xxxx.com');

$res = array();
$res['vals'] = $vals;
$response = json_encode($res, JSON_UNESCAPED_UNICODE);
print $response;

JSONP ではプリフライトは発生しません。

JSONPではプリフライトリクエストは発生しない


サンプルテンプレート一式
下記からダウンロードできます。
ダウンロードした zip ファイルをドキュメントルート上に展開し、それぞれのパラメータを指定すると動くかと思います。
demo_def.inc の define 値を自環境にあうよう修正すれば動作の確認はできます。

C_ASSETS_URI: assets へのパス
C_GLOBAL_TEMPLATE_PATH: 共通テンプレートへのパス
C_CROSSSITE_ORIGIN: クロスサイトのサンプルを動作させる場合に自身の URL を指定
C_CROSSSITE_DEST: クロスサイトのサンプルを動作させる場合にアクセス先 URL を指定

zip パスワードは pr_ajax です。


コメント