HTML フォームのデータを自動で保存する。(ローカルストレージを使用)
フォームの要素の値が変化するたびに呼び出され、ローカルストレージに保存する
webアプリの環境設定に利用するために書いてみた。
いつも少し書いては、試しながらコーディングする。
今回は、すべて頭の中で動かしながら書いてみた。
単純なミスが1つ、構造的な順序のミスが2つ、意外に少なかった。
ie は、form要素の onchange を拾えないらしいので、動かない
JSON.(stringify || parse) を利用しているので使えないものは、動かない。
追記
callBackFunction が動作するように追加した
disabled も追加。
/* HTMLのFORM要素のエレメントの変数の値をローカルストレージに自動的に保存。 formにonchangeイベントを仕掛け、変更があった場合 form.elements の名前を基準に オブジェクトにします。nameが複数ある場合は、配列となります。 「使い方」 // 初期設定 var obj = AutoFormController.create (form[, cbfunc[, disabled]]]); // 一時無効 obj.disabled = true; // 一時無効状態でも強制的に保存する obj.save (true); // form要素のエレメントの値を取得する var value = obj.getValues (); // form要素のエレメントに値を設定する obj.setValues ({hoge: [1,2,3], fuga: 'abc'}); //以下のようになる <input type="text" name="hoge" value="1"> ....1 <input type="radio" name="hoge" value="2">....checked <select name="hoge" multiple> <option value="1">1....selected <option value="2">2....selected <option value="3">3....selected </select> <input type="text" name="fuga" value=""> .... 'abc' <input type="checkbox" name="fuga" value="abc">.... checked */ (function () { function Afc (form, func, disabled) { this.form = form; this.func = func; this.disabled = disabled; } function setValue2 (es, vs) { var i, e, j, opts, o; var vlen; es = [].concat (es);//配列化 vs = [].concat (vs); vlen = vs.length - 1; for (i = 0; e = es[i]; i+= 1) { switch (e.type) { case 'radio' : case 'checkbox' : e.checked = (-1 < vs.indexOf (e.value)); break; case 'select-one' : case 'select-multiple' : opts = e.options; for (j = 0; o = opts[j++]; ) o.selected = (-1 < vs.indexOf (o.value)); break; default : e.value = vs[(vlen < i) ? vlen: i]; break; } } } function setValue (values) { var es = this.form.elements; var i, e, v; for (i = 0; e = es[i++]; ) if ('undefined' !== typeof (v = values[e.name])) setValue2 (e, v); } function vPush (e) { var vs = this; var nm = e.name; if (! nm) throw new Error ('Element has not a name.'); if ('undefined' === typeof vs[nm]) vs[nm] = e.value || ''; else vs[nm] = [].concat (vs[nm], e.value || ''); } //name が2つ以上ある場合は、値を配列にする function getValue () { var es = this.form.elements; var vs = { }; var e, i, j, opts, o; for (i = 0; e = es[i++]; ) { switch (e.tagName) { case 'INPUT' : case 'TEXTAREA' : case 'SELECT' : switch (e.type) { case 'button' : case 'submit' : case 'reset' : break; case 'radio' : case 'checkbox' : if (e.checked) vPush.call (vs, e); break; case 'select-one' : vPush.call (vs, e); break; case 'select-multiple' : opts = e.options; for (j = 0; o = opts[j++]; ) { if (o.selected) vPush.call (vs, { name: e.name, value: o.value }); } break; default : vPush.call (vs, e); } } } return vs; } //_____________________________________________ function save (coerce) { if (! coerce) if (this.disabled) return; localStorage.setItem ( this.form.id || this.form.name, JSON.stringify (getValue.call (this)) ); } function load (coerce) { if (! coerce) if (this.disabled) return; var d = localStorage.getItem (this.form.id || this.form.name); if (d) setValue.call (this, JSON.parse (d)); } function create (form, func, disabled) { if (arguments.length < 1 || 'FORM' !== form.tagName) throw new Error ('Not form HTML elements'); var id = form.id || form.name || null; var obj; if (null === id) throw new Error ('Form does not have a name.'); obj = new Afc (form, func || null, disabled || false); obj.load (); function cbFunc (event) { save.call (obj); if ('function' === typeof this.func) this.func.call (this, event); } form.addEventListener ('change', cbFunc, false); form = null; return obj; } //__________________________________ Afc.prototype.save = save; Afc.prototype.load = load; Afc.prototype.getValues = getValue; Afc.prototype.setValues = setValue; Afc.create = create; this.AutoFormController = Afc; }) ();