Ajax通信。でもProxy認証が・・・

XMLHttpRequestを利用したAjax通信では、同一ドメイン以外へのHTTPリクエストの発行が許可されていない。例えば自ドメインがlocalhostなのに、http://www.google.co.jpにアクセスするなんてことは一足飛びにはできないわけです。
というわけで通常はクライアント(javascript)からはサーバーにリクエストを投げてそこからGoogleに行く、というようなことをしないといけません(JSONPという方法はここではおいておいて・・)。
やってみましょう。画面に表示される「Googleロード」というボタンを押すとAjaxによってページの再描画なしにGoogleのトップページが表示されるというものです。実装はJSP&Servletでいきます。

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="Windows-31J" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
	"http://www.w3.org/TR/html4/loose.dtd">

<HTML>
<HEAD>
  <TITLE>Ajaxサンプル</TITLE>

  <META http-equiv="Expires" content="0">
  <META http-equiv="Pragma" content="no-cache">
  <META http-equiv="Cache-Control" content="no-cache">

  <script type="text/javascript" src="jquery-1.2.6.min.js"></script>
  <script type="text/javascript">
    $(function(){
      $('button').click(function(){
        $('#result').load("http://localhost:5555/SampleAjax/getgoogle");
      });
    });
  </script>
</HEAD>
<BODY>
  <BUTTON>Googleロード</BUTTON>
  <P id="result"></P>
</BODY>
</HTML>

次にサーバーサイドのプログラムです。commonsのHTTP Clientを利用しています。

public class GetGoogleServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {

		HttpClient client = new HttpClient();
		HttpMethod method = new GetMethod("http://www.google.co.jp");

		String responseMessage = null;
		try {
			client.executeMethod(method);
			responseMessage = method.getResponseBodyAsString();
		} finally {
			method.releaseConnection();
		}

		res.setContentType("text/html; charset=UTF-8");
		PrintWriter writer = res.getWriter();
		writer.println(responseMessage);
		writer.close();
	}
}

実行してみるとサーバーサイドで接続エラーが出ており、Googleへアクセスできていないようです。
理由は、うちの会社ではProxy認証が必要なのですがそれをしていないことです。しくしく。
というわけでサーバーサイドのプログラムを少し修正し、プロキシ認証を行います。

・・・略・・・
		HttpClient client = new HttpClient();
		client.getHostConfiguration().setProxy("proxy.some.company", 8080);  // 追加!
		client.getState().setProxyCredentials(AuthScope.ANY, new UsernamePasswordCredentials("username", "password"));  // 追加!

		HttpMethod method = new GetMethod("http://www.google.co.jp");
・・・略・・・

これで、うまくいきました!ヤッホゥー!!

jQueryのindex付きeach

jQueryのeachは便利なのでよく使います。

$.each(ary, function(){ alert($(this).val()); });

ただ、indexが欲しい時はこんな風にしてた。

var i=0;
$.each(ary, function(){
  alert(i + ' : ' + $(this).val());
  ++i;
});

しかしもっと簡潔に書けた!素敵だ♪

$.each(ary, function(i){ alert(i + ' : ' + $(this).val()); });

ちなみに$(this)だとjQueryオブジェクトになるけど、素のデータを使いたいときもある。そんな時は以下のようにする。

var ary = ['dog', 'pig', 'cat'];
$.each(ary, function(i, item){ alert(i + ' : ' + item); });


どうでもいいけど、rubyだとこんな風にかけるよ。雰囲気はよく似ています。

%w[dog pig cat].each_with_index{|item, i| puts "#{i} : #{item}"}

jQueryでのワイルドカードSelector

こんなHTMLがあった時に、最初の3つに対してのみ、とあるクリックイベントを設定したいという時がある。

<button id="btn1">ボタン1</button>
<button id="btn2">ボタン2</button>
<button id="btn3">ボタン3</button>
<button id="other">関係ないボタン</button>

そんな時、jQueryのselectorを使ってこんな風に設定できたらなぁと思っていた。が、こういうワイルドカードを使ったような指定はできない。

$('#btn*').click(function(){  });

無理かぁと思っていたら、別のやり方でいけました!

$(':button[id^=btn]').click(function(){  });

リファレンスをちゃんと読め、という話ですねw

jQuery1.3リリース

http://phpspot.org/blog/archives/2009/01/jquery13.html
また触ってみようっと。

追記 2009/1/20

jQuery日本語リファレンスも1.3対応されている!仕事が早い!!脱帽です。
http://semooh.jp/jquery/cont/doc/release_1.3/

もともと設定されているイベントハンドラより先に任意の関数が実行されるようにする

「もともと設定されているイベントハンドラをすり替える」を改良してみようと思います。この時のヤツはもともと設定されていた関数の変わりに自分で定義した関数にすり替えるというものでしたが、今回のはもともと設定されている関数も実行されるんだけど、それより先に自分で定義した関数が実行されるようにしてみます。
対象となるHTMLはこんな感じ。

<script type="text/javascript">
function show(message) {
  alert(message);
}
</script>
</head>
<body>
  <button onclick="show('クリック');">クリック</button>
  <button onclick="show('Click!');">Click!</button>
</body>

で、jQueryはこんな感じ。

var func = $('button').attr('onclick');
$('button').attr('onclick', '').bind('click', function(){alert('hello');}).bind('click', func);

これで出来た!と最初思っていたんですが、問題ハケーン。
「クリック」の方をクリックした時は「hello」「クリック」と表示されて予想通りだったんですが、「Click!」の方をクリックするとこっちも「hello」「クリック」となり、「Click!」とはなりませんでした。あれれ。
よくよく考えたら、ここの部分!

var func = $('button').attr('onclick');

「$('button')」で二つ分のボタンが取れるのに、onclick属性に対応する関数は最初の「クリック」の方しか取れてない。関数の配列とかが返ってこないといけないのでは。
といっても返ってこないので、何とかやってみました。これでうまくいきます。

jQuery.each($('button').get(), function(){
  var func = $(this).attr('onclick');
  $(this).attr('onclick', '').bind('click', function(){alert('hello');}).bind('click', func);
});

getメソッドを使って、一旦配列にするのがポイントです!

もともと設定されているイベントハンドラをすり替える

次のようなHTMLがあったとする。

<button id="hoge" onclick="hogehoge();">click!</button>

このボタンをクリックすれば当然hogehoge関数が実行される。
これを、HTML上のonclickを直接書き換えること無しに、fugafuga関数が呼ばれるようにすり替えたい。
jQueryのメソッドを調べていたらunbind/bindというのが使えそうだったので、やってみた。

$('#hoge').unbind("click", hogehoge).bind("click", fugafuga);

結果はhogehogeが呼ばれてから、fuagafugaが呼ばれた。unbindメソッドはbindメソッドで登録したもののみ削除できるようで、最初から登録されているhogehoge関数は削除されないみたい。
で、結局は以下のようにした。あんまりかっこよくないなぁ。もっといい方法がありそうな気もするけど。

$('#hoge').attr("onclick", "").bind("click", fugafuga);

alert等のウィンドウ内ダイアログを実現するjQueryプラグイン「jQuery Alert Dialogs」

http://phpspot.org/blog/archives/2009/01/alertjqueryjque.html

これはよさそう。
別にjavascriptのalertとかconfirmでいいやんと以前は思ってたんだけど、多国語対応アプリケーションを作った場合、confirm関数実行時のボタン「OK」「キャンセル」の「キャンセル」は変更できないんだな。
他は全部中国語表示されているのにここは「キャンセル」って出てちょっと間抜けな感じでした。IEの仕様ということで乗り切ったけど。