My Photo

May 08, 2015

JSONのオブジェクトは順序性を持たない

jQueryでリクエストを投げてPHPで配列のデータをJSON形式で返すアプリケーションを考える。

サーバ側のプログラムのサンプル。

$data = array('5' => array('areaName' => '大森')
            , '7' => array('areaName' => '蒲田')
            , '3' => array('areaName' => '大井町'));

print json_encode($data);

クライアント側のプログラムのサンプル。data はPOSTパラメータでサーバ側では使っていないが、Ajaxでサーバ側にパラメータを渡す例として書いておいた。

var url = "./ajax.php";
var data = { "mode" : "hoge" };
$.post(url, data,
  function(data) {
    for (var key in data) {
      alert("key=" + key + ",areaName=" + data[key].areaName);
    }
  },
  "json"
);

これを実行するとクライアント側ではサーバ側の元のデータの順序、つまり「大森」、「蒲田」、「大井町」と表示されると期待してしまうが、実際は「大井町」、「大森」、「蒲田」の順で表示される。
#Firefoxの場合。他のブラウザでは試していない。
原因はPHPの json_encode() がPHPの配列をJSONのオブジェクトに変換してしまうためである。実際のレスポンスのボディは以下のようになっている(デコードしてインデントを付けている)。

{
  "5": {
    "areaName": "大森"
  },
  "7": {
    "areaName": "蒲田"
  },
  "3": {
    "areaName": "大井町"
  }
}

これは3つのプロパティを持つJSONオブジェクトであり、配列ではないのでプロパティに順序なんてない。実際の出力の順序を見るとプロパティ名の降順で出力しているように見える。たまたまかもしれないが。

対策としては、サーバ側で json_encode() を使うのをやめて、PHPの配列を受け取ってJSON形式の配列を返す処理を自前で書けばいい。
修正したコードを以下に示す。下記のサーバ側コードで json_encode() の代わりの関数 json_array_encode() は汎用的なものではなく、配列のデータの形式が決まっているものとしてその形式だけにとりあえず対応したものである。json_array_encode() ではareaNameの値をUNICODEコードポイントの文字列に変換するために json_encode() を使っている。

サーバ側

$data = array('5' => array('areaName' => '大森')
            , '7' => array('areaName' => '蒲田')
            , '3' => array('areaName' => '大井町'));

print json_array_encode($data);

exit;

function json_array_encode($data) {
	$buf = array();
	
	foreach ($data as $k => $v) {
		$buf[] = '{"areaId":"' . $k . '","areaName":' . json_encode($v['areaName']) . '}';
	}

	return '[' . implode(',', $buf) . ']';
}

クライアント側

var url = "./ajax.php";
var data = { "mode" : "aaa" };
$.post(url, data,
  function(data) {
    for (var key in data) {
      alert("areaId=" + data[key].areaId + ",areaName=" + data[key].areaName);
    }
  },
  "json"
);

修正後のレスポンスのボディは以下のようにオブジェクトではなく配列となっている。
表示の順序は「大森」、「蒲田」、「大井町」とサーバ側のPHPの配列の順序どおりになる。

[
  {
    "areaId": "5",
    "areaName": "大森"
  },
  {
    "areaId": "7",
    "areaName": "蒲田"
  },
  {
    "areaId": "3",
    "areaName": "大井町"
  }
]

参考ページ: PHPと異なり,JavaScriptの連想配列とfor in構文には順序の概念がないので注意すること - プログラミングとIT技術をコツコツ勉強するブログ

October 19, 2014

HTML全体からjQueryオブジェクトを作成、find()とfilter()の違い

jQueryを使っていて予想と違っていたことがあったので検証した。使用したブラウザはFirefox32と33。

以下のようなhtmlのデータがある。表示のスクリーンショットはわかりやすいようにcssを付けてある。borderが破線になっているブロック要素はoptionクラスが付いている。

<!doctype html>
<html>
<head>
	<meta charset="UTF-8">
	<title>HTML5 Sample</title>
</head>
<body>
	<header>h</header>
	<section>s1</section>
	<section class="option">s2</section>
	<section>
		s3
		<div>s3_d1</div>
		<div class="option">s3_d2</div>
	</section>
	<section>
		s4
		<div>
			s4_d1
			<p>s4_d1_p1</p>
			<p class="option">s4_d1_p2</p>
		</div>
	</section>
	<section class="option">s5</section>
	<footer>
		f
		<div class="option">f_d1</div>
	</footer>
</body>
</html>

Response_html

上記のhtmlデータからoptionクラスを持つ要素をfind()、filter() で抜き出すJavaScriptコードを含むHTMLファイルと初期表示のスクリーンショットを以下に示す。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>find() と filter() の動作比較</title>
<script type="text/javascript" src="./js/jquery-1.8.2.min.js"></script>
<script type="text/javascript">
$(function() {
  $("input[type=button]").on("click", function() {
    name = $(this).attr("name");  // "find"または"filter"
    $("#funcName").text(name);  // 何を実行するかの表示
    $.get("./sample.html", function(responseBody) {
      var $responseBody = $(responseBody);
      var $result = $responseBody[name](".option");  // find()またはfilter()を実行
      $("#top").after($result);
    });
  });
});
</script>
<style type="text/css">
#top { width: 250px; border-style: solid; border-width: 4px; border-color: #ffff00; margin: 0px; }
header, footer { width: 250px; border-style: solid; border-width: 4px; border-color: #ff00ff; margin: 0px; }
section { width: 250px; border-style: solid; border-width: 4px; border-color: #ff0000; margin: 0px; }
div { width: 200px; border-style: solid; border-width: 4px; border-color: #00ff00; margin: 0px; }
p { width: 150px; border-style: solid; border-width: 4px; border-color: #0000ff; margin: 0px; }
.option { border-style: dashed; border-width: 2px; }
</style>
</head>
<body>
<section id="top">
  <form name="form" id="form" action="./get_html5.php" method="post">
    <input type="button" name="find" value="find">
    <input type="button" name="filter" value="filter">
    <span id="funcName"></span>
  </form>
</section>
</body>
</html>

Test_find_filter_0

ボタンを押すとAjaxで最初に示したHTMLデータを取得し、そのデータからjQueryオブジェクトを作成する。そして押したボタンに応じて find() または filter() でoptionクラス付きの要素を取得して表示している画面に追加する。
13行目で作成されたjQueryオブジェクト $responseBody の中身をfirebugsで見ると以下のようになっている。HTMLページ全体のデータからjQueryオブジェクトを作ると、head要素とbody要素の直下の要素が並んでいるのがわかる。head要素とbody要素は含まれていない。HTMLの構造そのままのjQueryオブジェクトが出来ると予想していたけど違った。なぜ head と body がないのかはよくわからないが、とりあえずそういうものだと思っておこう。

Watch_responsebody

findボタン押下(find()実行)後、filterボタン押下(filter()実行)後、それぞれ以下のようになる。

Test_find_filter_1
Test_find_filter_2

上記の結果から、find() と filter() で選択されるoptionクラス付きの要素はbody要素の子要素をLV1とすると、
find() で選択されるのが

LV2:<div class="option">s3_d2</div>
LV3:<p class="option">s4_d1_p2</p>
LV2:<div class="option">f_d1</div>

filter で選択されるのが

LV1:<section class="option">s2</section>
LV1:<section class="option">s5</section>

である。
以上より、find() と filter() の違いは以下になる。

find()
jQueryオブジェクトの直下の要素の子孫要素から要素を選択する。直下の要素は対象外である。この記事の例では $responseBody の直下の要素である meta,title,header,section,footer は選択処理の対象外であり、それらの子孫要素が選択の対象となる。
つまり find() は直下より下の子孫要素すべてから指定した条件の要素を選択する。
filter()
直下の要素から選択する。それらの子孫は対象外である。この記事の例では $responseBody の meta,title,header,section,footer が選択処理の対象となる。
呼び出し元のjQueryオブジェクトの集合から引数のセレクタに合うものだけを残し、合わないものはふるい落とす。名前の通りフィルタリングすると覚えるといい。
セレクタ1を要素セレクタ、セレクタ2をクラスセレクタまたは属性セレクタとすると
$(【セレクタ1】【セレクタ2】)

$(【セレクタ1】).filter(【セレクタ2】)
は同じになる。

参考ページ:
.find() | Qrefy - jQuery日本語リファレンス
.filter() | Qrefy - jQuery日本語リファレンス
jQuery の解釈するHTML 文字列 - do_akiの徒然想記

October 10, 2014

jQueryのセレクタについてメモ

基本だけどよく忘れるのでメモ。

セレクタでマッチした要素の存在チェック

やり方はいくつかあるようだが、自分としては下記のやり方が一番わかりやすいかなと。

$(<セレクタ>).length > 0

逆に「セレクタにマッチする要素がない」という条件は次のように書ける。

$(<セレクタ>).length == 0

参考ページ:jQueryによる要素の存在チェックまとめ: 小粋空間


セレクタ間の関係

セレクタ間の記号意味
スペース子孫
>親子
,OR
+直後
~兄弟

否定のセレクタ

:not(セレクタ)

属性セレクタのand

以下のように書くと属性セレクタを間を空けずに連続して書くと、属性セレクタを条件をANDで連結したセレクタとなる。

[属性名1=属性値1][属性名2=属性値2][属性名3=属性値3]...

参考ページ:Qrefy - jQuery日本語リファレンス

September 28, 2014

選択リストを拡張するSelect2

Select2はjQuery UIで選択リスト拡張するライブラリ。選択リストで複数選択可能な場合、便利そうだなと。
複数選択可能な場合のサンプルコード test_select2.html を以下に示す。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Select2のテスト</title>
<meta http-equiv="content-style-type" content="text/css" />
<meta http-equiv="content-script-type" content="text/javascript" />
<link type="text/css" rel="stylesheet" href="/css/jquery-ui-1.10.4.min.css" />
<link type="text/css" rel="stylesheet" href="/css/select2.css" />
<script type="text/javascript" src="/js/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="/js/jquery-ui-1.10.4.min.js"></script>
<script type="text/javascript" src="/js/select2.min.js"></script>
<script type="text/javascript">
$(function() {
  $("#select2Test").select2();
});
</script>
<style type="text/css">
.result { width: 300px; min-height: 100px; border: solid 2px; }
</style>
</head>
<body>
<div>
<form action="./select2_test_2.php" name="form" id="form" method="post">
<p>
	<select multiple="multiple" name="select2Test[]" id="select2Test" style="width: 300px;">
		<option value="">--</option>
		<optgroup label="自動車">
			<option value="7201">日産自動車</option>
			<option value="7203">トヨタ自動車</option>
			<option value="7267">本田技研工業</option>
		</optgroup>
		<optgroup label="空運">
			<option value="9202">ANAホールディングス</option>
		</optgroup>
		<optgroup label="通信">
			<option value="9432">NTT</option>
			<option value="9433">KDDI</option>
			<option value="9984">ソフトバンク</option>
		</optgroup>
	</select>
</p>
<input type="submit" value="submit" />
</form>
</div>
</body>
</html>

select要素のname属性に "[]" が付いているのに注意。複数選択可能なので配列形式にしないと選択された項目をすべて取得することができない。

ファイルは以下のように配置した。Select2 の画像ファイルを /css/images に置いたので、select2.css の画像を指定している部分のパスを書き換えた。
ダウンロードした select2 のzipファイルには画像ファイルは下記にある以外に selec2x2.png というのも含まれているが、なくても特にエラーにならなかった。

[ドキュメントルート]
├[css]
│├[images]
││├jQuery UI の画像ファイル
││├select2.png
││└select2-spinner.gif
│├jquery-ui-1.10.4.min.css
│└select2.css
└[js]
  ├jquery-1.9.1.min.js
  ├jquery-ui-1.10.4.min.js
  └select2.min.js

2つの項目を選択すると下のようになる。選択を解除するには項目名のラベルにある×印をクリックする。

Select2_sample_1

ここで、入力フィールドをクリックすると、選択リストは下のようになる。既に選ばれている項目は選択肢から取り除かれている。

Select2_sample_2

また、入力フィールドに文字を入力すると、その文字によって下のよう選択肢が絞り込まれる。

Select2_sample_3

現在選択されている項目をjQueryで以下のように取得できる。val属性の値を取得するということか。

$("#select2Test").select2("val"));

選択するコードは以下になる。1個だけ選択するなら第2引数を配列にする必要はない。

$("#select2Test").select2("val", ['9432', '9433', '9984']);

選択リストの拡張ライブラリには他に Chosen というのがある。自分は使ってないが Chosen を使ったページを触ってみたら、選択肢が日本語だと選択肢の絞込みはできないようだった。

参考ページ:
Select2 3.5.1
[JS]セレクトボックスの使い勝手をパワーアップするスクリプト -Select2 | コリス
セレクトボックスを100倍使い易くする!! | CoDE4U

June 16, 2014

JavaScriptの正規表現で前方一致(後読み)が使えない

関連記事:正規表現メモ

タイトルの通り、"(?<=abc)xyz" のような「前方一致指定(肯定後読み)」が使えなかった。"(?<!abc)xyz" のような「前方不一致指定(否定後読み)」も同様。
「後方一致指定(肯定先読み)」は普通に使えた。

April 10, 2014

Deferredで無限ループしてポーリング

以前の関連する記事:
jQueryで非同期な処理が終わるのを待つにはDeferredを使う
Deferredの復習
Deferredの復習2:jQueryのAjax関数はPromiseを実装したjqXHRを返す

「一定間隔でポーリングして処理の進行状況をチェックし、処理中ならば『処理中です』と画面に表示し、処理が終わったらポーリングをやめて『処理が完了しました』と表示させる。」というようなことをやりたい。 参考ページにDeferredを使った無限ループの実装があったので、それをベースにして考えてみた。
まず、スリープ関数とその使用例。

function mySleep(time) {
  return (
    function() {
      var dfd = $.Deferred();
      setTimeout(
        function() {
          console.log("resolve() [" + time + "sec]:" + new Date().toLocaleString());
          dfd.resolve();
        },
        time * 1000);
      return dfd.promise();
    });
}

function outputLog(msg) {
  return (
    function() {
      console.log("log: " + msg + " : " + new Date().toLocaleString());
    });
}

function testFunc() {
  $.ajax({
      url: "http://testhoge.jp/get_status.php",
      type: "POST",
      dataType: "json"
    })
  .then(
    function(data, status, xhr) {
      console.log("resolved: status=" + status + "[" + xhr.status
                  + "] data.status=" + data.status
                  + " :" + new Date().toLocaleString());
    },
    function(xhr, status, thrown) {
      console.log("rejected: status=" + status + "" + xhr.status
                  + "] :" + new Date().toLocaleString());
    })
  .then(mySleep(5))
  .done(outputLog("done"))
  .fail(outputLog("fail"));
}

上記の testFunc はリクエストが成功すると38行目の then に渡された mySleep(5) が実行された5秒間待ち、それから outputLog("done") が実行される。
リクエストが失敗すると mySleep(5) はスキップされ、ただちに outputLog("fail") が実行される。

これを踏まえて、「処理が終わるまでポーリング」の実装(script要素内)を以下に示す。

$(function() {
	polling();
});

function mySleep(time) {
  return (
    function() {
      var dfd = $.Deferred();
      setTimeout(
        function() {
          dfd.resolve();
        },
        time * 1000);
      return dfd.promise();
    });
}

// 3秒毎にポーリング
function polling() {
  $.ajax({
      // 処理の状態を取得するサービスにアクセス
      url: "http://testhoge.jp/get_status.php",
      type: "POST",
      dataType: "json"
    })
  .then(
    function(data, status, xhr) {
      // 取得したデータの内容によってDeferredの状態を変更する
      var d = $.Deferred();
      if (data.status === "completed") {
        d.reject();
      } else {
        d.resolve();
      }
      
      // Promiseを返す
      return d.promise();
    })
  .then(mySleep(3))
  .done(polling)
  .fail(
    function () {
      $("#running").hide();   // 「実行中」を非表示にする
      $("#completed").show(); // 「完了」を表示する
    });
}

初期状態で id="runnning" のdiv要素が表示されていて id="completed" のdiv要素は非表示になっている。
画面のロードが完了すると polling が実行されてリクエストが実行される。レスポンスが帰ってくると33行目の then に渡された関数が実行される。その関数はレスポンスの値が "completed" でなければresolvedなDeferredから作成したPromiseを返す。すると、次の then に渡された mySleep(3) が実行されて3秒間待った後、次の行の done に渡された polling が再帰呼び出しされる。このように3秒間隔でポーリングされる。
レスポンスが "completed" の場合はrejectedなPromiseが返されるので、mySleep(3) は実行されず、fail に渡された関数がただちに実行されて、実行中であることを示している部分を非表示にして、完了したことを知らせる要素を表示する。

別にDeferredを使わなくても setInterval() でいいような気もするが、setInterval() には指定したcallback関数の処理に時間がかかる場合に問題があるというような記事もちらほら見かける。詳しいことは setInterval() を使ったことがないのでよくわからないが。

参考ページ:
jQuery.Defferredを使ったdone無限ループとSleepで簡単ポーリング - それマグで!

April 09, 2014

jQueryのAjax関数はPromiseを実装したjqXHRを返す

以前の関連する記事:
jQueryで非同期な処理が終わるのを待つにはDeferredを使う
Deferredの復習

jqXHR

jQueryのAJAX関数(ajax(),get(),put())はjqXHRオブジェクトを返す。jqXHRはPromiseを実装している。
このjqXHRはAjax関数によるリクエストが成功するとresolvedになり、失敗するとrejectedになる。よって下記の2つのコードは同様な動作となる。

// success,errorプロパティを使用
$.ajax({
    url: "http://testhoge.jp/test.php",
    type: "POST",
    data: data,
    success: function(data, status, xhr) {
      console.log("success: status=" + status + "[" + xhr.status + "]");
    },
    error: function(xhr, status, thrown) {
      console.log("error: status=" + status + "[" + xhr.status + "]");
    },
    dataType: "text"
  });
// Deferredのdone(),fail()を使用
$.ajax({
    url: "http://testhoge/test.php",
    type: "POST",
    data: data,
    dataType: "text"
  })
.done(
  function(data, status, xhr) {
    console.log("done: status=" + status + "[" + xhr.status + "]");
  })
.fail(
  function(xhr, status, thrown) {
    console.log("fail: status=" + status + "[" + xhr.status + "]");
  });

参考ページ:
Deferredまとめ | Qrefy - jQuery日本語リファレンス
Ajaxまとめ | Qrefy - jQuery日本語リファレンス
jQuery モダンAjaxな書き方を目指して -Deferredを使ったAJAX- - Hack Your Design!
結局jQuery.Deferredの何が嬉しいのか分からない、という人向けの小話 - Qiita

April 06, 2014

Deferredの復習

以前の関連する記事:jQueryで非同期な処理が終わるのを待つにはDeferredを使う

以前、jQueryのDeferredについての記事を書いて、大雑把には理解できた。
Deferredについて最もわかりやすい解説は参考1,2だと思う。概念的には決して難しくないのだが、Deferredのメソッドが各々どんな引数を取り、どんな値を返すのかとか、日本語のリファレンスを読んでも読み取れなかった(書いてなかった?)こととかがある。
そういうところをところをあらためてまとめた。

DeferredとPromise

Deferred.promise() が返すPromiseオブジェクトとは何か。以前の記事では参考3から下記の引用を示した。

Promiseは、ユーザがDeferredの状態の変更を防ぐための、Deferredのメソッドのサブセット(then,done,fail等)を提供する。

で、それってつまりどういうことかというと、参考2から引用すると

.promise()という謎のメソッドが書かれていますが、これはDeferredオブジェクトから.resolve()や.reject()といった「状態を変更するメソッド」を取り除いたサブセットを返します。Deferredオブジェクトを直接返してしまうと、受け取った側で状態を変更できてしまい、非同期処理そのものが本当に終わったのかどうか保証が取れなくなります。これを防ぐため、.promise()によるクリーニング作業が必要になるわけです。

とのこと。つまり、Promiseオブジェクトは done() や fail() は持ってるけど resolve() や reject() は持っていない。なのでDeferredではなくPromiseを渡しておけば、渡した先で勝手に状態を変更されたりしなくて安心、ってこと。なるほど。

Diferred.then

Diferred の then() はdone() と fail() を一度にできて便利、というだけではなかった(jQuery1.8以降)。
done() と fail() が返す値は元のPromiseそのものである(Deferredではなくて?)。単純に return this している。
対して、then() は新たなPromiseを作成して返す。
また、then() に普通の関数を渡した場合とPromiseを返す関数を渡した場合も動作が違う。
これら違いについて下記の3つの関数を使って具体的に説明する。

/**
 * 2秒後にコンソールに出力する。必ずresolveする。
 * Promiseを返す。
 * @returns Promise
 */
function delayHello() {
	var d = new $.Deferred;
	setTimeout(function() {
		console.log('Hello!');
		d.resolve();
	}, 2000);
	return d.promise();
}

/**
 * 3秒後に(以下同文)
 */
function delayHello3000() {
	var d = new $.Deferred;
	setTimeout(function() {
		console.log('Hello!');
		d.resolve();
	}, 3000);
	return d.promise();
}

function hello() {
  console.log('Hello! sync');
}

下記は done() でメソッドチェーンを作成している。

delayHello()
.done(delayHello)
.done(delayHello);

この場合、2行目のdone() が返すのは最初の delayHello() が返すPromise(p1と呼ぶ)なので、2行目の done() も3行目の done() も同じp1に対する処理である。よって、p1がresolvedになると2行目の done() に渡された delayHello と 3行目 done() に渡された delayHello が間を置かずに続けて実行される。
consoleには以下のように出力される。

Hello!  ←2秒後
Hello!  ←4秒後
Hello!  ←4秒後

下記は then() に普通の関数を渡してメソッドチェーンを作成している。

delayHello()
.then(hello)
.then(hello);

then() に普通の関数を渡すと、then() が返すPromiseは前のPromiseとは異なるオブジェクトであるが、状態は引き継ぐ。上のコードでは最初の delayHello() が返すPromiseがresovedになると、2行目の then() が返すPromiseも直ちにresolvedとなり、結果として2行目の hello() と3行目の hello() は間を置かず続けて実行される。
consoleには以下のように出力される。

Hello!       ←2秒後
Hello! sync  ←4秒後
Hello! sync  ←4秒後

下記は then() にPromiseを返す関数を渡してメソッドチェーンを作成している。

delayHello()
.then(delayHello)
.then(delayHello);

2行目の then() が返すPromiseは(p3と呼ぶ)、最初の delayHello() が返すPromise(p1と呼ぶ)と2行目の then() に渡された delayHello() が返すPromise(p2と呼ぶ)の両方と関連のあるPromiseで、p1 と p2 の両方がresolovedになると p3 もresolvedになる。よって、3つのdelayHello() は2秒の間隔を開けて順番に実行される。
consoleには以下のように出力される。

Hello!  ←2秒後
Hello!  ←4秒後
Hello!  ←6秒後

結局、then() で処理を連結するとなにがうれしいかというと、「順番に非同期処理を行う」コードを「コールバック地獄」(参考2)にならず直感的に書けるということのようだ。
「処理を直列に連結」という説明がイメージ的にわかりやすい。

$.when

when() は引数に1個以上のオブジェクトを取り、渡されたオブジェクトをまとめたPromiseを返す。
引数がDeferredまたはPromiseの場合、引数のオブジェクトがすべてresolvedになると、返されたPromiseもresolovedになる。引数のオブジェクトのうち1つでもrejectedになると、返されたオブジェクトはrejectedになる。
引数がDeferred、Promiseではない場合、resolvedなものとして扱われる。
when() は、then() による「直列の連結」に対して「並列の連結」と言われる。when() を利用するケースとしては、複数の非同期処理を実行し、すべての非同期処理が終了したところで新たな処理を行うことが考えられる。

$.when(delayHello(), delayHello3000())
.done(hello);

上記のコードでは、delayHello() の返すPromiseと delayHello3000() が返すPromiseの両方がresolovedになると、done() で渡された hello() が実行される。以下のように出力される。

Hello!       ←2秒後
Hello! 3000  ←3秒後
Hello sync   ←3秒後

参考ページ:
1.爆速でわかるjQuery.Deferred超入門 - Yahoo! JAPAN Tech Blog
2.JavaScriptとコールバック地獄 - Yahoo! JAPAN Tech Blog
3.Types | jQuery API Documentation
4.$.when() - jQuery API Documentation 日本語訳
5.jQuery.DeferredとかjQuery.whenの使い方について - 一から勉強させてください( ̄ω ̄;)

January 05, 2014

confirm()をjquery.alerts.jsで代替する

WEBアプリケーションで確認ダイアログにはJavaScriptの window.confirm() を使うが、表示されるダイアログのデザインやボタンの文言を変更などいったカスタマイズはできない。
そこで jquery.alerts.js の jConfirm() で代替する。

jquery.alerts.js は公式ページがすでになくなっていてるので開発は停止しているようだ。しかし、404ページの下にarchivesというリンクがあって、その先のページでダウンロードできる。
注意点は以下。
・要jQuery UI。
・新しいjQuery(1.9.0以降?)では動かない。廃止されたメソッドを使用しているのが原因のようだ。

<link rel="stylesheet" href="css/jquery_ui/jquery-ui.css" type="text/css" />
<link rel="stylesheet" href="css/jquery_ui/jquery.alerts.css" type="text/css" />
<script type="text/javascript" src="js/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="js/jquery_ui/jquery-ui.custom.js"></script>
<script type="text/javascript" src="js/jquery.alerts.js"></script>
<script type="text/javascript">
function customConfirm(param) {
	jConfirm('Can you confirm this?', 'タイトル', function(r) {
		console.log("param=[" + param + "],r=[" + (r == true ? "true" : "false") + "]");
	});
}
</script>
</head>
<body>
<form name="form" action="/test.php" method="post">
<input type="button" value="確認1" onclick="customConfirm('abc');" /><br />
</form>

ダイアログのデザインは jquery.alerts.css を編集してカスタマイズできる。
ただし、ボタンの「OK」、「Cancel」の文言は jquery.alerts.js に書いてあるのでそれを編集する。
以下、jquery.alerts.css の一部を抜き出してシンプルにしたサンプル。

<link rel="stylesheet" href="css/jquery_ui/jquery-ui.css" type="text/css" />
<script type="text/javascript" src="js/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="js/jquery_ui/jquery-ui.custom.js"></script>
<script type="text/javascript" src="js/jquery_ui/jquery.ui.draggable.js"></script>
<script type="text/javascript" src="js/jquery.alerts.js"></script>
<script type="text/javascript">
function customConfirm(param) {
	jConfirm('Can you confirm this?', 'タイトル', function(r) {
		console.log("param=[" + param + "],r=[" + (r == true ? "true" : "false") + "]");
	});
}
</script>
<style type="text/css">
#popup_container {
    min-width:300px; /* Dialog will be no smaller than this */
    max-width:600px; /* Dialog will wrap after this width */
    border:solid 5px #999;
    background:#fff;
    color:#000;
    -moz-border-radius:5px;
    -webkit-border-radius:5px;
    border-radius:5px;
}
#popup_title {
    margin:0; padding:0;
    border:solid 1px #fff;
    border-bottom:solid 1px #999;
    background:#ccc;
    color:#666;
    font-size:14px;
    font-weight:bold;
    text-align:center;
    line-height:1.75em;
    cursor:default;
}
#popup_content {
	margin:0; padding:1em 1.75em;
/*	background:transparent url("img/icon/color/information.png") no-repeat 16px 16px;	*/
}
#popup_message { padding-left:20px; }
#popup_panel { text-align:center; margin:1em 0 0 1em; }
</style>
</head>
<body>
<form name="form" action="/test.php" method="post">
<input type="button" value="確認1" onclick="customConfirm('abc');" /><br />
</form>

jQueryUIについての参考サイト:
jQuery UI
jQuery UI 導入方法

参考サイト:
ウィンドウ、モーダル|jQuery plugin|Ajax|PHP & JavaScript Room
非常にきれいなアラートを表示する「jQuery Alert Dialogs」-JavaScript Library Archive
">

November 19, 2013

Object.keys()をjQueryで代替する

以下のJavaScriptのコードが Firefox だと問題なく実行できたのだがIE8(OS:Windows XP SP3)ではエラーになった。

var obj = { 0 : "a", 1 : "b", 2 : "c"};
alert(Object.keys(obj));

Object.keys() はIE9からサポートとのこと。
ググってIE8でも動く方法がないか調べたら、以下の方法を見つけた。jQueryすばらしい。

var obj = { 0 : "a", 1 : "b", 2 : "c"};
var objKeys = $.map(obj, function(value, key) {
	return key;
});
alert(objKeys);

参考サイト:
Using jQuery 1.6 to find an array of an object's keys >> Encosia
Object.keys 関数 (JavaScript)

June 2021
Sun Mon Tue Wed Thu Fri Sat
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30      
無料ブログはココログ

日本blog村

  • にほんブログ村 IT技術ブログへ
  • にほんブログ村 アニメブログへ
  • にほんブログ村 サッカーブログ アルビレックス新潟へ

好きな音楽家

メモ

XI-Prof