以下に示すリスト(members.jsファイル)は、前回示したmembers.aspxファイルを呼び出したり、[login]ボタンやメンバー名のclickイベントを処理したりするJavaScriptコードだ。
(function () { ← (1)
var login = document.getElementById('login');
var member_name = document.getElementById('member_name');
var changeUI = function(f) { ← (2)
var uielems = [['labelMember', 'inline', 'none'],
['labelPsw', 'inline', 'none'],
['labelName', 'none', 'inline'],
['commands', 'none', 'block'],
['rosters', 'none', 'block']];
for (var i = 0; i < uielems.length; i++) {
var elem = document.getElementById(uielems[i][0]);
elem.style.display = f ? uielems[i][1] : uielems[i][2];
}
login.value = f ? 'login' : 'logout';
};
var nullToEmpty = function(val) {
return (val == null) ? '' : val;
};
login.addEventListener('click', function() { ← (3)
if (login.value == 'login') {
var member = document.getElementById('member');
var psw = document.getElementById('psw');
if (member.value != '') {
var xtr = new XMLHttpRequest(); ← (4)
xtr.onload = function() { ← (5)
var result = JSON.parse(xtr.responseText); ← (6)
if (result.id != null) {
member_name.innerHTML = Util.htmlEscape(result.name); ← (7)
member_name.href = "members.aspx?q=edit";
changeUI(false);
document.getElementById('update_rosters').click();
} else {
psw.value = '';
}
};
Util.postData(xtr, 'members.aspx',
'id=' + encodeURIComponent(member.value) + '&psw=' + encodeURIComponent(psw.value)); ← (8)
}
} else { // logout
var xtr = new XMLHttpRequest();
Util.postData(xtr, 'members.aspx', 'logout=true'); ← (9)
changeUI(true);
document.getElementById('rosters').innerHTML = '';
}
});
member_name.addEventListener('click', function(e) {
var xtr = Util.createXtr(function() {
var member = JSON.parse(xtr.responseText);
if (member.name == null) {
changeUI(true);
document.getElementById('rosters').innerHTML = '';
}
Dialog.show('<div>' + member.name + '</div>' ← (10)
+ '<form method="post" id="member_form">'
+ '<label>郵便番号<input type="text" name="zip" placeholder="郵便番号" size="8"/></label><br/>'
+ '<label>住所<input type="text" name="address" placeholder="住所" size="64"/></label><br/>'
+ '<label>パスワード更新<input type="checkbox" name="update_psw" value="true"/></label>'
+ '<input type="text" name="psw" placeholder="password"/></form>',
{
load: function(popup) {
var form = document.getElementById('member_form');
var elems = ['zip', 'address'];
for (var i = 0; i < elems.length; i++) {
form.elements[elems[i]].value = nullToEmpty(member[elems[i]]);
}
},
unload: function(popup) {
var form = document.getElementById('member_form');
var xtr = new XMLHttpRequest();
var data = 'zip=' + encodeURIComponent(form.elements['zip'].value)
+ '&address=' + encodeURIComponent(form.elements['address'].value)
+ '&save=true';
if (form.elements['update_psw'].checked) {
data += '&psw=' + encodeURIComponent(form.elements['psw'].value)
}
Util.postData(xtr, member_name.href, data);
}
}
);
});
xtr.open('GET', member_name.href, true);
xtr.send(null);
e.preventDefault();
});
var xtr = Util.createXtr(function() {
var recs = JSON.parse(xtr.responseText);
var opt = [];
for (var i = 0; i < recs.length; i++) {
opt[i] = '<option value="' + recs[i].id + '">'
+ Util.htmlEscape(recs[i].name) + '</option>';
}
document.getElementById('member').innerHTML = opt.join('');
});
xtr.open('GET', 'members.aspx', true);
xtr.send(null);
})();
ここで示したmembers.jsファイルは、ロードされると同時に、定義した無名関数がそのまま実行される。
実行した結果、いくつかのローカル関数を定義し、DOMのイベントハンドラーに関数を追加する。これらはローカル関数ではあるが、HTMLと同じ寿命を持つDOMにイベントハンドラーとして組み込まれるので、HTMLと同じ寿命を持つこととなる。
このような方法を利用することで、グローバルなネームスペースを汚染せずに、HTMLの表示期間中持続する関数やオブジェクトを定義する。
以下は筆者自身が経験したJavaScriptのバグパターンであって、他の開発者が必ずしも同じパターンにはまり込むことはないかもしれないが、参考のために示す。
var result = document.getElementById('number_data').value * 32; // 文字列の数字データと32の乗算
// 上から文字列が数値の場合、数値との演算が行われると想定すると+は異なる
result = document.getElementById('number_data').value + 32; // 文字列と文字列化された'32'の連結となる
if ('0' == some_variable) { // some_variableが文字列の'0'でなくともtrueとなることがある。例えば数値の0やfalseである*1
*1 文字列と文字列の比較を行う場合は、===を利用する。'0' == false → true、'0' === false → false。
Copyright© Digital Advantage Corp. All Rights Reserved.