クロージャ(その2)

イントラで業務アプリケーションで凝った動きをしなくってもこれは使えるって言うサンプルです。
Webアプリケーションで複数回のサブミットを不可にすることってよくありますよね。そういう場合、ブラウザ側での対処はサブミットされたときに全てのサブミットの元となるボタンなどの要素を使えなくしたり、フラグを立てて次からのサブミットはできないように大抵します。今回は後者のフラグを立てて使えないようにするサンプルです。
通常はたぶんこんな感じ。

<script type="text/css">
    var submited = false;
    function formsubmit(){
        if(submited){
            return false;
        }
        submited = true;
        return true;
    }
</script>

<!-- HTML〜 -->

<form onsubmit="return formsubmit();">

しかし、これだと全ての form タグに同じ呼び出しを書く必要があり、 submited というスコープの広い変数が作られてしまいます。余り美しくありません。ですので、これを以下のようにしてみます。

window.addEventListener("load",function(){
    var submithandler = getSubmitHandler();
    var forms = document.getElementsByTagName("form");
    for(var i = 0; i < forms.length; i++){
        forms[i].addEventListener("submit",submithandler,false);
    }
},false);

function getSubmitHandler(){
    var submited = false;
    return function(e){
        if(submited){
            //イベントキャンセル処理
            return false;
        }
        submited = true;
        return true;
    }
}

ココでは何をしているかって言うと、まず window の load イベントにメソッドを登録しています。 load イベントの時に呼び出されるメソッドの中では、サブミットを補足するメソッドを取得しています。こいつが前回書いたクロージャってやつです。そして全ての form タグの要素を探し出して一つずつにそのクロージャをサブミットされたときのイベントハンドラに登録しています。
サブミットされたときのイベントハンドラはクロージャで取得していますのでインスタンスは一つです。ですのでメソッドの内部にある submited 変数もインスタンスが同じになり、どの form タグで呼ばれてもその値は共有されます。そのため初回のサブミットでは値は false ですが、そのまま true に更新されてしまうため、2度目のサブミットはキャンセルされてしまいます。

いかがでしょうか?コードは少し長くてほんのちょっと複雑になったように見えてしまいますが、こうしておくことで全ての form タグにメソッドを呼び出しを書く必要がなく、記述漏れもなくなります。またこれを外部ファイルとして定義しておき、全ての画面でインクルードするようにしておけばさらに効率のいいものになるでしょう。また、対象としたくないものがある場合は form タグの class 属性などにダブルサブミットを許可するような記述をしておき、それを判断してイベントハンドラを登録しないなどの処理もできます。