ko.utils(その他)
これはKnockoutJSアドベントカレンダー8日目の記事です。
KnockoutJS Advent Calendar 2014 - Qiita
今日は Knockout の便利機能が入った ko.utils について適当に紹介します。
前回は配列だったのでそれ以外を紹介します。
ソースコードはここ。
https://github.com/knockout/knockout/blob/master/src/utils.js
紹介するのは以下のメソッドです。
- ko.utils.extend
- ko.utils.fieldsIncludedWithJsonPost
- ko.utils.getFormFields
- ko.utils.peekObservable
- ko.utils.postJson
- ko.utils.postJson
- ko.utils.parseJson
- ko.utils.stringifyJson
- ko.utils.range
- ko.utils.registerEventHandler
- ko.utils.triggerEvent
- ko.utils.unwrapObservable
- ko.utils.objectForEach
- ko.utils.toggleDomNodeCssClass
- ko.utils.addOrRemoveItem
それでは順番にいきましょう。
- ko.utils.extend
Objectを拡張します。
サンプル
var target = {a:1, b:2} var option = {d:3, e:4, f:5, a:6} var result = ko.utils.extend(target, option); console.log(result);
結果
Object {a: 1, b: 2, d: 3, e: 4, f: 5}
- ko.utils.fieldsIncludedWithJsonPost
これはメソッドではなく配列です。あとで出てくる ko.utils.postJson のデータを送信するときに自動的に含めるフィールド名が入ってます。
fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],
軽くググった感じだとRailsのCSRF対策で自動的に埋め込まれるトークン用、もう一つは ASP.NETでリクエストの検証トークン用っぽいです。
- ko.utils.getFormFields
フォームから指定した文字列もしくは正規表現に一致するフィールドを配列で返します。
HTML
<form id="form1" action="/" method="post"> <input type="text" name="f1" value="" /> <input type="checkbox" name="f2" value="" /> </form>
var form = document.getElementById("form1"); var result1 = ko.utils.getFormFields(form, "f2"); console.log("result1 length: " + result1.length); console.log("result1: " + result1[0].getAttribute("name")); var result2 = ko.utils.getFormFields(form, /f[12]/); console.log("result2 length: " + result2.length); console.log("result2: " + result2[0].getAttribute("name")); console.log("result2: " + result2[1].getAttribute("name"));
結果
result1 length: 1 result1: f2 result2 length: 2 result2: f2 result2: f1
- ko.utils.peekObservable
ko.observableの peek() と同じです。
<div id="peekObservable"> <p>ko.utils.peekObservable</p> <form id="form1" action="/" method="post"> <input type="text" name="f1" value="" data-bind="value: input1"/> <input type="text" name="f2" value="" data-bind="value: input2"/> <p data-bind="text: result"></p> <input type="checkbox" name="f3" value="1" data-bind="checked: input3" id="chk"/><label for="chk">ここを押せば更新される</label> </form> <script> function ViewModel() { var self = this; self.input1 = ko.observable(); self.input2 = "Input 2"; self.input3 = ko.observable(false); self.result = ko.pureComputed(function(){ var i1 = ko.utils.peekObservable(self.input1); // self.input.peek() と同じ var i2 = ko.utils.peekObservable(self.input2); // observableじゃなくても使える(無視される) var checked = self.input3(); return i1 + " - " + i2 + " " + checked; }); } ko.applyBindings(new ViewModel(), document.getElementById('peekObservable')); </script> </div>
- ko.utils.postJson
ko.utils.postJson(urlOrForm, data, options)
urlOrForm
URLかフォーム要素をいれる
data
送信するデータ。Modelでもいいけどprototypeで継承してきたプロパティも送信するってソースに書いてる
送信する値は ko.utils.stringifyJson で JSON化される
options
オブジェクトで指定する。配列でもいけるかもしれないけど試してない。
指定できるオプションは次のとおり
params
送信するパラメータ。dataとほぼ一緒だけどこちらは JSON化しない
includeFields
送信する対象のフィールドを配列で指定する
指定がない場合は自動的に以下のフィールドが指定される(CSRF対策のため)
authenticity_token
__RequestVerificationToken_ から始まるフィールド
submitter
これに内部で作成したフォームを引数として渡して実行する
<form id="sendForm" action="/"> <input type="text" name="includeField1" value="1" /> <input type="text" name="includeField2" value="2" /> <input type="text" name="excludeField1" value="3" /> <input type="text" name="excludeField2" value="4" /> <input type="text" name="otherField" value="5" /> </form> <script> var model = {a:{b:"bb",c:["cc1","cc2"]}, d:["ddd"]}; var mySubmitter = function(data){ console.log(data); }; ko.utils.postJson(document.getElementById('sendForm'), model, {params: {x:'xx', y:'yy'}, includeFields: [/includeField[0-9]/, 'otherField'], submitter: mySubmitter}); </script>
結果(内部で生成されてPOSTされるフォーム)
<form action="http://localhost:8080/" method="post" style="display: none;"> <input type="hidden" name="a" value="{"b":"bb","c":["cc1","cc2"]}"> <input type="hidden" name="d" value="["ddd"]"> <input type="hidden" name="x" value="xx"> <input type="hidden" name="y" value="yy"> <input type="hidden" name="otherField" value="5"> <input type="hidden" name="includeField1" value="1"> <input type="hidden" name="includeField2" value="2"> </form>
- ko.utils.parseJson
内部的に JSON.parse が呼ばれるのでほぼ同じものとして利用すればよい。
違いは引数をJSON.parseする前にトリムすることと、JSON.parseに対応していない古いブラウザにも対応していること
古いブラウザはあんまり安全でない(Fallback on less safe)と書いてある
- ko.utils.stringifyJson
JSON.stringifyを内部で呼び出すのでほぼ同じものとして利用すればよい
違いは IE8より前だとエラーをメッセージ付きで投げることと、
JSON.stringifyに渡すJavaScriptオブジェクトを ko.utils.unwrapObservableしてから渡す
- ko.utils.range
ko.utils.range(min, max)
最小(min)から最大(max)までの範囲の値を配列にして返します
var result = ko.utils.range(2, 5);
console.log(result);
結果
[2, 3, 4, 5]
- ko.utils.registerEventHandler
要素にイベントハンドラを登録できる
<button id="btnClick">Click</button> <script> console.log("ko.utils.registerEventHandler"); ko.utils.registerEventHandler(document.getElementById('btnClick'), 'click', function(){ alert('clicked!'); }); </script>
- ko.utils.triggerEvent
イベントをディスパッチできる。
<button id="btnClick">Click</button> <script> console.log("ko.utils.registerEventHandler"); ko.utils.registerEventHandler(document.getElementById('btnClick'), 'click', function(){ alert('clicked!'); }); ko.utils.triggerEvent(document.getElementById('btnClick'), 'click'); </script>
- ko.utils.unwrapObservable
ko.unwrapはこれのショートカット。observableは値を取り出すときに unwrapしないと取り出せない。
とはいえ observable でないものを手動で unwrap する判断が間違え易いのでこのメソッドがあると思ってる。
例えば
self.a = ko.observable();
で宣言した変数の値を取り出すときは
self.a()
としてやらないといけないが、
self.b = 1;
で宣言した変数の値を取り出すときに
self.b();
とするとエラーになるため。
- ko.utils.objectForEach
オブジェクトのプロパティをぐるぐるする
<script> var obj = {a:1, b:2, c:3}; ko.utils.objectForEach(obj, function(item, index){ console.log(index + ":" + item); }); </script>
結果
1:a 2:b 3:c
- ko.utils.toggleDomNodeCssClass
jQueryでいう removeClass や addClass ができる
$(element).addClass(value); $(element).removeClass(value)
KnockoutJS
ko.utils.toggleDomNodeCssClass(element, value, true); ko.utils.toggleDomNodeCssClass(element, value, false);
<style> .add { color: red; } .remove { text-decoration:line-through; } </style> <span id="myText" class="remove">Hello</span> <script> ko.utils.toggleDomNodeCssClass(document.getElementById('myText'), 'add', true); ko.utils.toggleDomNodeCssClass(document.getElementById('myText'), 'remove', false); </script>
- ko.utils.addOrRemoveItem
配列に特定の要素を追加もしくは削除する
ko.utils.toggleDomNodeCssClass の内部や
"checked" のバインディングハンドラでモデルが更新されたときにチェックボックスを更新するのに使われている
APIは以下のようになる
ko.utils.addOrRemoveItem(array, value, included)
サンプル
var arr = ["aaa","bbb"]; ko.utils.addOrRemoveItem(arr, "ccc", true); console.log(arr); ko.utils.addOrRemoveItem(arr, "bbb", false); console.log(arr);
結果
["aaa", "bbb", "ccc"] ["aaa", "ccc"]
明日は @hkusu_ さんの 「ko.editables で入力をロールパックしてみる」です!
よろしくお願いします!