jQueryで要素の置換は、replaceAllやreplaceWithを使う。
replaceWithを使う例として、div要素の置換は、よく見かけるけど、select要素の置換はあまり見かけなかったので、メモっとく。
「radioタイプのinput要素(ラジオボタン)を変更した場合に、他のselect要素を選択できなくさせたい」って時に、disabledにするとグレーアウトされて、見た目の変更ができなくて困った。
で考えたのが、readonlyで行こうと。(submitされるけどね)
readonlyなら、フォントの色の変更とかができて自由だし。
でも、select要素には、readonlyがない。
ということで、select要素をtextタイプのinput要素(テキストボックス)に置換して、readonlyにすることで、落ち着いた。
jQueryならシンプルで簡単にできると思ったら、functionの実行時に、DOM操作が即時反映されないことが仇になり、結構苦戦。
素のJavaScriptでやってしまったら負けだと思って、追求したら、なんとかできた。
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Example</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript">
var example = {
/**
* idをキーにtextタイプのinput要素に置換したselect要素を保持する連想配列.
*/
clonedSelects: {}
,
/**
* select要素をtextタイプのinput要素に置換する.
* @param id select要素のid
* @param value 固定のvalueを指定する(未指定の場合、現在選択中のvalueが設定される)
*/
replaceToText:
function (id, value) {
// id内の.(ドット)はエスケープ
var elem = $('#' + id.replace(/\./g, '\\.'));
// select要素でない場合、処理終了
if (elem[0].nodeName != 'SELECT') {
return;
}
example.clonedSelects[id] = elem.clone(true);
// 固定のvalueを設定
if (typeof value !== 'undefined') elem.val(value);
// select要素のvalue値をhiddenで持つ
var elemHidden = $('<input type="hidden"/>');
// replaceWithを行うまではidが重複するため、別のidにする
elemHidden.attr('id', id + 'Hidden');
elemHidden.attr('name', elem.attr('name'));
elemHidden.val(elem.val());
elem.after(elemHidden);
// select要素をtextタイプのinput要素に置換
elem.replaceWith(function (elem, id) {
var elemText = $('<input type="text"/>').attr({readonly: 'readonly', tabindex: '-1'});
elemText.val(elem.children(':selected').text());
elemText.attr('style', elem.attr('style'));
// textタイプのinput要素にするため、id,nameを変更
elemText.attr('id', id + 'Text');
elemText.attr('name', elem.attr('name') + 'Text');
return elemText;
}(elem, id));
// replaceWithを行った後、select要素のidをhiddenへ設定
elemHidden.attr('id', id);
}
,
/**
* textタイプのinput要素をselect要素に戻す.
* "戻す"と記載しているのは、select要素を保持しているのが前提のため。
* @param id 戻すselect要素のid
* @param value 固定のvalueを指定する(未指定の場合、現在選択中のvalueが設定される)
*/
replaceToSelect:
function (id, value) {
// select要素を保持する連想配列に存在しない場合、処理終了
if (typeof example.clonedSelects[id] === 'undefined') {
return;
}
// id内の.(ドット)はエスケープ
var elemHidden = $('#' + id.replace(/\./g, '\\.'));
// replaceWithを行うとidが重複するため、事前に別のidにする
elemHidden.attr('id', id + 'Hidden');
// 固定のvalueを設定
if (typeof value !== 'undefined') elemHidden.val(value);
// id内の.(ドット)はエスケープ
var elem = $('#' + id.replace(/\./g, '\\.') + 'Text');
elem.replaceWith(function (id, value) {
var elemSelect = example.clonedSelects[id];
// select要素に戻すため、idも戻す
elemSelect.attr('id', id);
elemSelect.val(value);
return elemSelect;
}(id, elemHidden.val()));
// select要素に戻したため、保持していたselect要素を削除
delete example.clonedSelects[id];
// select要素に戻すため、hiddenを削除
elemHidden.remove();
}
}
</script>
</head>
<body>
<input type="radio" name="radioexample" onclick="example.replaceToSelect('example');" checked="checked" />select要素へ置換
<input type="radio" name="radioexample" onclick="example.replaceToText('example')" />textタイプのinput要素へ置換
<br />
<select id="example" name="example">
<option>サンプル1</option>
<option>サンプル2</option>
<option>サンプル3</option>
</select>
</body>
</html>
(注)select要素の置換なので、textタイプのinput要素を初期表示としたい場合、onloadでtextタイプのinput要素とすること。
(注)id内のドットのエスケープは、Strutsなどを使用していない限り、なくてもOK。
JavaScriptライブラリを比較するときに、役に立った本。
jQuery、Prototype、Dojo、YUI、script.aculo.usを比較してる。
今は、jQuery優勢かな。