• このエントリーをはてなブックマークに追加

はじめに

特定の郵便番号指定時にインタラクティヴになってくれなかったようなので,修正を加えました.

原因

このライブラリは,7桁の郵便番号,仮に 123-4567 とします,を与えたとき,特定のディレクトリ (以下,データディレクトリ.デフォルトではライブラリの入っているディレクトリ下の data ディレクトリ) の中の zip-***.json というファイル,この例では zip-123.json,を探し,その中のJSONデータから必要な情報を引っ張ってくるようになっています.

さて,冒頭で触れた「特定の郵便番号」,3桁部分が 199 や 200 のものがその例ですが,データディレクトリを覗いてみると,これらに対応する zip-199.jsonzip-200.json といったファイルが存在していませんでした.

おそらく,すべての登録されている郵便番号の 3桁部分が 001 ~ 999 のすべてをカバーするわけではなく,そのカバーされないものについては,zip-***.json なファイルが存在しない,または 更新ツール で生成されない,ということになりましょうか.

そんなことからライブラリのソースコード,Ajax処理部分を確認したところ,気になる部分がありました.

    if ( window.Ajax && Ajax.Request ) {
        ...
        var opt = {
            method: 'GET',
            asynchronous: true,
            onComplete: func2
        };
        new Ajax.Request( url, opt );
    }
    else if ( window.jQuery ) {
        ...
        jQuery.getJSON( url, func3 );
    }

Ajaxリクエスト失敗時における処理が定義されていないようですね.これで冒頭の原因を特定できたっぽいです.

対策

上記部分を,Ajaxリクエスト失敗時にも対応できるようにしました.

    var func_error = function( xhr ) {
        return callback( { result: AjaxZip2.RESULT.NOT_FOUND } );  // 前エントリを参照
    };
 
    if ( window.Ajax && Ajax.Request ) {
        ...
        var opt = {
            method: 'GET',
            asynchronous: true,
            onComplete: func2,
            onFailure: func_error
        };
        new Ajax.Request( url, opt );
    }
    else if ( window.jQuery ) {
        ...
        jQuery.ajax({
          url:      url,
          type:     'get',
          dataType: 'json',
          success:  func3,
          error:    func_error
        });
    }

ソースコード

オリジナルとの差分であるパッチと,それを実際にあてたものを,CodeReposにコミットしておきました.オリジナルが置いてあるディレクトリに branches/patch-20090224 というディレクトリを作成し,その中に置いてあります.

オリジナルとの差分

diff --git a/ajaxzip2.js b/ajaxzip2.js
index 462a2f1..4acac87 100755
--- a/ajaxzip2.js
+++ b/ajaxzip2.js
@@ -43,21 +43,32 @@ AjaxZip2.PREFMAP = [
     '福岡県',   '佐賀県',   '長崎県',   '熊本県',   '大分県',
     '宮崎県',   '鹿児島県', '沖縄県'
 ];
-AjaxZip2.zip2addr = function ( azip1, apref, aaddr, azip2, astrt, aarea ) {
+AjaxZip2.RESULT = {
+    FOUND:          0, // 住所が見つかった
+    NOT_FOUND:      1, // 住所が見つからなかった
+    SAME_AS_PREV:   2, // 郵便番号が前回の検索と同じ
+    NULL:           3, // 郵便番号か空
+    INVALID_FORMAT: 4, // 郵便番号の書式が不正
+
+    HOGE:           undefined
+};
+
+AjaxZip2.zip2addr = function ( azip1, apref, aaddr, azip2, astrt, aarea, callback ) {
     var fzip1 = AjaxZip2.getElementByName(azip1);
     var fzip2 = AjaxZip2.getElementByName(azip2,fzip1);
     var fpref = AjaxZip2.getElementByName(apref,fzip1);
     var faddr = AjaxZip2.getElementByName(aaddr,fzip1);
     var fstrt = AjaxZip2.getElementByName(astrt,fzip1);
     var farea = AjaxZip2.getElementByName(aarea,fzip1);
-    if ( ! fzip1 ) return;
-    if ( ! fpref ) return;
-    if ( ! faddr ) return;
+    if( typeof callback == 'undefined' ) callback = function() {};
+    if ( ! fzip1 ) return callback( { result: AjaxZip2.RESULT.HOGE } );
+    if ( ! fpref ) return callback( { result: AjaxZip2.RESULT.HOGE } );
+    if ( ! faddr ) return callback( { result: AjaxZip2.RESULT.HOGE } );
 
     // 郵便番号を数字のみ7桁取り出す
     var vzip = fzip1.value;
     if ( fzip2 && fzip2.value ) vzip += fzip2.value;
-    if ( ! vzip ) return;
+    if ( ! vzip ) return callback( { result: AjaxZip2.RESULT.NULL } );
     var nzip = '';
     for( var i=0; i<vzip.length; i++ ) {
         var chr = vzip.charCodeAt(i);
@@ -65,27 +76,28 @@ AjaxZip2.zip2addr = function ( azip1, apref, aaddr, azip2, astrt, aarea ) {
         if ( chr > 57 ) continue;
         nzip += vzip.charAt(i);
     }
-    if ( nzip.length < 7 ) return;
+    if ( nzip.length < 7 ) return callback( { result: AjaxZip2.RESULT.INVALID_FORMAT } );
 
     // 前回と同じ値&フォームならキャンセル
     var uniq = nzip+fzip1.name+fpref.name+faddr.name;
     if ( fzip1.form ) uniq += fzip1.form.id+fzip1.form.name+fzip1.form.action;
     if ( fzip2 ) uniq += fzip2.name;
     if ( fstrt ) uniq += fstrt.name;
-    if ( uniq == AjaxZip2.prev ) return;
+    if ( uniq == AjaxZip2.prev ) return callback( { result: AjaxZip2.RESULT.SAME_AS_PREV } );
     AjaxZip2.prev = uniq;
 
     // JSON取得後のコールバック関数
-    var func1 = function ( data ) {
+    var func1 = function ( data, _callback ) {
+      
         var array = data[nzip];
         // Opera バグ対策:0x00800000 を超える添字は +0xff000000 されてしまう
         var opera = (nzip-0+0xff000000)+"";
         if ( ! array && data[opera] ) array = data[opera];
-        if ( ! array ) return;
+        if ( ! array ) return _callback( { result: AjaxZip2.RESULT.NOT_FOUND } );
         var pref_id = array[0];                 // 都道府県ID
-        if ( ! pref_id ) return;
+        if ( ! pref_id ) return _callback( { retulr: AjaxZip2.RESULT.HOGE } );
         var jpref = AjaxZip2.PREFMAP[pref_id];  // 都道府県名
-        if ( ! jpref ) return;
+        if ( ! jpref ) return _callback( { result: AjaxZip2.RESULT.HOGE } );
         var jcity = array[1];
         if ( ! jcity ) jcity = '';              // 市区町村名
         var jarea = array[2];
@@ -144,15 +156,20 @@ AjaxZip2.zip2addr = function ( azip1, apref, aaddr, azip2, astrt, aarea ) {
         } else if (cursor.setSelectionRange) {
             cursor.setSelectionRange(len,len);
         }
+
+        if( typeof _callback == 'function' ) {
+          _callback( { result: AjaxZip2.RESULT.FOUND, data: data[nzip] } );
+        }
     };
 
     // 郵便番号上位3桁でキャッシュデータを確認
     var zip3 = nzip.substr(0,3);
     var data = AjaxZip2.CACHE[zip3];
-    if ( data ) return func1( data );
+    if ( data ) return func1( data, callback );
 
     // JSONファイルを受信する
     var url = AjaxZip2.JSONDATA+'/zip-'+zip3+'.json';
+    var func_error = function( xhr ) { return callback( { result: AjaxZip2.RESULT.NOT_FOUND } ); };
 
     if ( window.Ajax && Ajax.Request ) {
         // JSONファイル受信後のコールバック関数(Prototype.JS用)
@@ -162,12 +179,13 @@ AjaxZip2.zip2addr = function ( azip1, apref, aaddr, azip2, astrt, aarea ) {
             var json = AjaxZip2.getResponseText( req );
             data = eval('('+json+')');
             AjaxZip2.CACHE[zip3] = data;
-            func1( data );
+            func1( data, callback );
         };
         var opt = {
             method: 'GET',
             asynchronous: true,
-            onComplete: func2
+            onComplete: func2,
+            onFailure: func_error
         };
         new Ajax.Request( url, opt );
     }
@@ -176,9 +194,15 @@ AjaxZip2.zip2addr = function ( azip1, apref, aaddr, azip2, astrt, aarea ) {
         var func3 = function (data) {
             if ( ! data ) return;
             AjaxZip2.CACHE[zip3] = data;
-            func1( data );
+            func1( data, callback );
         };
-        jQuery.getJSON( url, func3 );
+        jQuery.ajax({
+          url:      url,
+          type:     'get',
+          dataType: 'json',
+          success:  func3,
+          error:    func_error
+        });
     }
 };

おわりに

以上,インタラクティヴさは 前エントリ とまったく変わりませんが不具合っぽいものが 1つなくなりました.

ホントのところは,失敗時に XMLHttpRequest オブジェクトのステータスコードとかで分岐してごにょごにょする必要がありそうですが,まぁその辺は省略しときます.

最後に,2000000 という郵便番号を入力し,指摘いただいた方に感謝.