Webの入力フォームに値を設定するスマートな方法

テキストボックス, テキストエリア, SELECTボックス, チェックボックス, ラジオボタンなどの、HTMLの入力フォームに値を設定する「いい」方法についてです。 (「いい」というのは私の主観なので、本当にいいかどうかは読んだ方が判断してください)

利用シーンとしては、

などが考えられます。

以下の「sample」SELECTボックスで何か選択すると、選択肢に対応して用意している値が入力されます。 これを実装する場合にあなただったらどう書くか、少し考えてみてください…。

sample
名前

スキル Java JavaScript Ruby C
希望年収
希望勤務地
コメント

コードの紹介

私が紹介・お勧めするのは以下のコードです。「どの要素に何を設定するか」という情報は データと考え、処理とは分離しJSONで表現しています。「$(function() {});」の中身は SELECTボックスを作っている処理です。

なので、記述する処理は実質的には「setValues」の部分だけです。 処理内容はシンプルなので、ソースを見る人も理解しやすいのではないかと思います。

$(function() {
	// SELECTボックスの中身の作成と選択時の挙動の設定。
	for (var key in samples) {
		$("#samples").append($('<option>').val(key).html(key));
	}
	$("#samples").change(function() {
		var sample = samples[$("#samples").val()];
		setValues(sample);
	});
});

/**
 * FORMコントロールへの値の設定
 * @param setting 「{key1: value1, key2: value2, ...}」形式のオブジェクト
 *   key  :要素を特定するjQueryのセレクタ
 *   value:設定する値
 */
var setValues = function(settings) {
	$.each(settings, function(key, val) {
		var elm = $(key);
		if (typeof val === "boolean") {
			elm.prop("checked", val);
		} else {
			elm.val(val);
		}
	});
};

// データ。SELECTボックスもこの情報をもとに作成する
var samples = {
	"" : {},
	"IDで指定": {
		"#fullname": "柳 政和",
		"#male": true,
		"#skill-Java": true,
		"#skill-JavaScript": true,
		"#skill-Ruby": false,
		"#skill-C": false,
		"#select": "750",
		"#multiselect": "東京",
		"#textarea": "いろいろやってます",
	},
	"nameで指定": {
		"[name='fullname']": "池澤 彩",
		"[name='gender']": ["female"],
		"[name='skill']": ["JavaScript", "Ruby"],
		"[name='select']": "500",
		"[name='multiselect']": ["東京","名古屋", "鳥取"],
		"[name='textarea']": "電子工作もできます",
	},
	"nameで指定2": {
		"[name='fullname']": "増井 雄一",
		"[name='gender'][value='male']": true,
		"#skill-Java": true,
		"#skill-JavaScript": false,
		"#skill-Ruby": true,
		"#skill-C": true,
		"[name='select']": "1000",
		"[name='multiselect']": ["東京", "大阪", "博多"],
		"[name='textarea']": "風呂でもコードを書きます!",
	},
};

他の人の実装でしばしば見かけるのは、要素のIDと値を引数にとり処理をする関数をつくり、 設定したい入力欄ごとにその関数を呼ぶというものです。そのタイプだと項目が一つ増えるたびに 関数を呼び出す処理を1行追加しなくてはならず、関数化している意味がほとんどないといえるでしょう。

それに対し上記の方法だと、項目が増えた場合にはJSONオブジェクトに対応するデータを 追加するだけでよく、処理の部分は原則的に修正を加える必要がありません。 さらにSELECTボックスもJSONを元に作成するので、選択肢を増やす場合でもHTMLを編集する手間が省けます。

ちなみにsetValuesで「$(key)」を一旦変数に入れているのは、値をセットした後にonchangeやonblurを発生させるなど 将来、拡張しやすくするためです。また、チェックボックスとラジオボタンで、 name属性・value属性がない場合、checkedで値を設定したい場合のためにと 汎用性を高めるためのロジックになっています。それらがなくていいのなら、以下のようなさらにシンプルなコードにできます。

var setValues = function(settings) {
	$.each(settings, function(key, val) {
		$(key).val(val);
	});
};

このケースに限らないことですが、私はプログラムを書く際に処理とデータの分離が重要 だと考えています。この「setValues」はその象徴的ともいえる実装です。

データと処理を分離すれば、処理をシンプルに書けるのでコーディング量が減り、 またバグも減ります。さらに項目追加の際には変更個所が明確なので修正が容易で、 かつ処理に手を加える必要がないのでデグレも減るでしょう。 その代わり、処理とデータを分離するスキルや適切なデータ構造を考えるスキルが必要になりますが、 そこは経験を重ね少しずつ身に付けていけばいいと思います。

ここで紹介した方法は、このサイトの多くのツールでも実装しています。 私の場合、セレクタを書くのが楽なのでID指定で書くことが多いのですが、checkboxの場合はname指定が便利ですね。 入力項目が一つしかない場合はシンプル実装にしていたり、選択項目をグルーピングしているケースやなど いくつかバリエーションがあります。ご興味があればソースをのぞいてみてください。

2016/02/28