さとやn Blog

試合はRuby,勝負はC#!

JavaScript

jQuery: live関数でまだ存在しない要素に対してイベントを設定する

Ajaxを使用していると、動的に追加されたコンテンツにボタンとかリンクとかがあって、そいつらにイベントハンドラを設定したい場合が多々あると思います。
私はこれまでは、Ajaxで取得したコンテンツをページに追加した後に、イベントハンドラを設定するコードを書いていたのですが、これって結構コードが美しくなかったりします。
でも、まあ、仕方ないよなー、とか思っていたのですが,jQueryのliveメソッドを使用すると、簡単に解決できてしまうことを発見。
ドキュメントを読むと、
	Attach a handler to the event for all elements which match the current selector, now and in the future.
現在及び将来において存在する要素に対してイベントハンドラを設定することができる、とのこと。
これは素晴らしい、と言うことで早速やってみる。
「追加」をクリックすると、Ajaxで部分コンテンツを取得して、ページに追加して、「削除」をクリックするとその要素が消える、といった感じのページを作ってみる。
31)

live関数を使用しない場合は、こんな感じで、部分コンテンツ取得後に「削除」リンクのイベントを設定するコードを書いてました。
	$(function(){
		
		//「追加」リンクをクリックで 簡単なDIV要素をAjaxで取得してドキュメントに追加するだけ
		$("#addLink").click(function(){
			$.get("./get_partial_content", function(html){
				$(document.body).append($(html));
				
				//削除リンクのイベント設定
				$(".deleteLink").click(function(){
					$(this).parent().remove();
				})
]			});
		});
		
	})
でも、この書き方だと、要素を追加するたびに、既存の削除リンクに対してもイベントハンドラを追加し続けてしまいます。この例では要素が削除されてしまうので、眼に見える害はありませんが、もしアラートを表示するような内容にした場合、何度も同じアラートが表示されるような削除リンクができあがってしまいます。
できればページ初期化時にイベント関連はまとめて設定しておきたいところです。
で、それを可能にしてくれるのがlive関数、というわけで、コードを次のように書き換えてみる。

	$(function(){
		
		//「追加」リンクをクリックで 簡単なDIV要素をAjaxで取得してドキュメントに追加するだけ
		$("#addLink").click(function(){
			$.get("./get_partial_content", function(html){
				$(document.body).append($(html));
			});
		});
		
		//上記のイベントで動的に追加されたDIV要素の「削除」リンクをクリックすると、自分自身(と親DIV)をドキュメントから削除する
		$(".deleteLink").live("click", function(){
			$(this).parent().remove();
		});
	})
	
こうすると、動的に追加されたコンテンツ内の class="deleteLink" の要素に対してもイベントハンドラが設定されます。
素晴らしい!

超簡単にHTMLテーブルでエクセルのオートフィルタみたいなのを実現するライブラリ

仕事でHTMLテーブルでエクセルのオートフィルタのようなものを使いたい、という要望があり、多分探せばそんなスクリプトがあるんじゃないかと思い探したところやっぱりありました。
http://www.javascripttoolbox.com/lib/table/index.php

これは、tableやth要素にclass属性でtable-autofilterとかtable-filterableとしてあげるだけで, ソートやらフィルタリングやらページングやら(いずれもクライアント側で処理)を簡単に装備できてしまうという超スグレモノです。

早速やってみる。
まずソースをダウンロードして、とりあえず table.js という名前で保存してインクルード。JavaScriptに関してはこれだけで、自分でなにか書く必要とかはありません。

	<%= javascript_include_tag "table.js" %>	

次に、フィルタリングしたいテーブルのclass属性に class="table-autofilter" を追加して、フィルタしたい列のthに class="table-filterable"を指定。
こんな感じでしょうか、、。

 

<table class="table-autofilter">
  <thead>
    <th class="table-filterable">文字列</th>	 

※テーブルヘッダは thead, データ行は tbodyに書かないとダメなようです。JavaScriptソース見たらそうなってました、、、。

適当にデータを作って、ページを表示してみる。

22)
35)
 00)
06)

素晴らしい!

JavaScriptで無効な日付の生成を避ける

JavaScriptで無効な日付の検証をする必要があったのですが、
例えばRubyのDateクラスの場合、下記のような2010/2/30という日付を指定すると、ちゃんとエラーになってくれます。

52)

でも、JavaScriptの場合は、これは2010/3/2と解釈されてしまいます。
※JavaScriptのMonthは0ベースのインデックスなので、-1してやる必要があります。2月を指定する場合は1にしなければなりません。

15)


で、JavaScriptでもRubyのDateクラスと同様に無効な日付の場合は、エラーにしてくれないかな、ということでファクトリメソッドを追加して独自に検証をするようにしてみました。
ついでに、月を-1するのは直感的でないため、それもファクトリメソッドに任せるようにしました。どう考えてもこっちの方が直感的ですよね。
 
 
Date.create = function(year, month, day){
    var result = new Date(year, month-1 ,day);
    if(result.getFullYear() != year || result.getMonth() != month-1 || result.getDate() != day)
        throw "invalid date";
    return result;
}

これを実際に動かしてみると、

50)


ちゃんとえらーになります。

 

ChromeのJavaScriptコンソールで複数行のScriptを実行

FireFoxのFireBugでは簡単に複数行に渡るJavaScriptの入力&実行が出来るのですが、Chormeでは普通にやると、こんな感じでエラーになってしまいます。
59)

Alt + Enter でいけるんですね、、、。ってだいぶ前にやって駄目だったような気がしたんだけど、、、。今やったらうまくいきました。

28)


 更に最新版では、JavaScriptコンソールを Alt + Command + j で一発で呼び出せるようになったのは嬉しいです。Windows版は前からできたけど、マック版は最新の6からできるようになったようです。

プラグインなしでHTMLテーブルを簡易編集

簡単なものなら、プラグインなしでも実現できそうなのでやってみました。
要望としては、エンターキーで上下できれば、ということでしたので、それならば、ということで。
jQueryのnext, prevメソッドは便利ですね。
テーブルの方は、最初からinput要素で出力して、CSSで見た目を平坦な表に見せかけます。
で、JavaScriptでCSSをちょこっと変更して、あとはinput要素のreadonly属性をon/offします。

全体のソースを貼りつけようとしたら、文字数オーバーとかいって更新できないので、JavaScriptの部分だけ貼りつけます。
エンターキーでの移動をなくせばほとんどCSSクラスの追加・削除だけです。

42)
58)

 
        <script type="text/javascript" charset="utf-8">
            $(function(){
                $(".editable input").attr("readonly", "readonly").keypress(function(e){
                    if(e.keyCode == 13){

                        var className = e.target.className;

                        var next = null;
                        if(e.originalEvent.shiftKey){
                            next = $(e.target).parent().parent().prev();
                        }else{
                            next = $(e.target).parent().parent().next();
                        }

                        if(next){
                            $("input[class='" + className + "']", next).focus();
                        }
                    }
                });
                
                $("#linkEdit").click(function(){
                    $(".editable input").addClass("editable").attr("readonly", '')
                }
                
                $("#linkEdit2").click(function(){
                   $(".editable input").removeClass("editable").attr("readonly", true);
                });
            })
        </script>
livedoor プロフィール
QRコード
QRコード
  • ライブドアブログ