Knockout.js を勉強したときのメモ。
Knockout.js とは
クライアントサイドの JavaScript MVVM フレームワーク。
Backbone.js と比べると、データバインディングなどの機能が備わっているなどやや高機能で、
Angular.js と比べると機能が少ない分簡潔で覚えることが少なく、かつ軽量という特徴がある。
Hello World
インストール
公式サイト より js ファイルをダウンロードする。
実装
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<h1 data-bind="text: message"></h1>
</body>
</html>
window.onload = function() {
var viewModel = {message: 'Hello Knockout.js!!'};
ko.applyBindings(viewModel);
};
動作確認
説明
- Knockout.js では、 ViewModel は普通の JavaScript オブジェクトを使用する。
- ViewModel と View を紐付けるには、
ko.applyBindings()
関数を使用する。 - View (HTML)では、
data-bind
属性を使用して ViewModel の値の出力を定義する。 - この時点では、 JavaScript 側の値が変わっても、 View の表示がリアルタイムで更新されることはない(observable を使用する)。
入力フォームに出力する
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<input type="text" data-bind="value: message" />
</body>
</html>
window.onload = function() {
var viewModel = {message: 'Hello Knockout.js!!'};
ko.applyBindings(viewModel);
};
-
data-bind="value: xxxx"
とすることで、入力フォームに出力できる。
双方向のデータバインディング
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<input type="text" data-bind="value: message" />
<button id="button">...</button>
</body>
</html>
window.onload = function() {
var viewModel = {
message: ko.observable('Hoge')
};
ko.applyBindings(viewModel);
document.getElementById('button').onclick = function() {
alert('viewModel.message=' + viewModel.message());
};
};
↓テキストボックスの内容を書き変えてから、ボタンをクリック
-
ko.observable()
関数を ViewModel のプロパティに設定することで、そのプロパティの双方向のバインディングが可能になる。 -
ko.observable()
の引数には、初期値を設定する。 -
ko.observable()
の戻り値は関数になっていて、引数を渡すかどうかによって getter と setter の振る舞いをする。-
viewModel.message()
のように引数を渡さずに実行した場合は、プロパティの値を取得する。 -
viewModel.message('aaa')
のように引数を渡して実行した場合は、プロパティに値を設定する。
-
- このように、 Knockout.js の監視対象となり双方向のデータバインディングが可能になったプロパティを
Observable
と呼ぶ。
複数の Observable を組み合わせた別の Observable を定義する
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<input type="text" data-bind="value: hoge" />
<input type="text" data-bind="value: fuga" />
<span data-bind="text: piyo"></span>
</body>
</html>
window.onload = function() {
var ViewModel = function() {
this.hoge = ko.observable('Hoge');
this.fuga = ko.observable('Fuga');
this.piyo = ko.computed(function() {
return this.hoge() + this.fuga();
}, this);
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
};
↓Hoge の値を変更する
↓Fuga の値を変更する
-
ko.computed()
関数を使うと、他の Observable を複数組み合わせた、別の Observable を定義できる。 -
ko.computed()
の第1引数には評価結果を返す関数を、第2引数には第1引数の関数内で使用するthis
が参照するオブジェクトを渡す。 - 評価関数内で他の Obervable の getter を使用すると、その Observable が変更されるたびに評価関数がコールバックされるようになる。
computed の仕組み
computed()
が、どうやって他の Observable の変更と連動しているのかの仕組みについて。
以下のようなロジックで連動が行われている。
-
computed()
に渡された評価関数を実行する。 - 実行中に呼び出された Obervable を依存対象として記録する。
- 2で記録した Observable の値が変更された場合は、依存対象の Observable をクリアして1に戻る。
ステップ3で一旦依存する Observable をクリアしているため、評価関数が実行されるたびに依存する Observable が更新されることになる。
これによって、動的に依存する Observable が切り換わる場合にも対応できるようになっている。
しかし、言い換えるとしょっぱなの compute() の呼び出して getter が実行されなかった Obervable は、連動の対象外となる ことを意味する。
window.onload = function() {
var ViewModel = function() {
this.flag = ko.observable(true);
this.hoge = ko.observable('hoge');
this.fuga = ko.observable('fuga');
this.piyo = ko.computed(function() {
return this.flag() ? this.hoge() : this.fuga();
}, this);
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
};
- 初回の
computed()
の実行では、this.hoge()
しか実行されない。 - したがって、
fuga
の値が変更されてもcomputed()
に渡した評価関数は実行されない。
テキスト及び表現
表示・非表示の切り替え
window.onload = function() {
var ViewModel = function() {
this.isTrue = true;
this.isFalse = false;
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<span data-bind="visible: isTrue">isTrue</span>
<span data-bind="visible: isFalse">isFalse</span>
</body>
</html>
-
visible
バインディングを使うと、 DOM 表示・非表示を切り替えられる。 - パラメタ(
isTrue
,isFalse
)には、任意の式を渡すことができる。
HTML を出力する
window.onload = function() {
var ViewModel = function() {
this.message = '<b>binding</b>';
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<span data-bind="html: message">isTrue</span>
</body>
</html>
-
html
バインディングで、 HTML をそのまま出力することができる。 - サニタイズはされないので、信頼できる HTML だけを出力するように注意しなければならない。
CSS クラスを設定する
クラス名を直接指定する
window.onload = function() {
var ViewModel = function() {
this.cssClass = 'error italic'
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
<style>
.error {
color: red;
}
.italic {
font-style: italic;
}
</style>
</head>
<body>
<span data-bind="css: cssClass">error message</span>
</body>
</html>
-
css
バインディングを使うと、 CSS クラスを設定することができる。 - パラメタには、クラス名を文字列でそのまま指定する。
クラスごとに boolean で有効・無効を指定する
window.onload = function() {
var ViewModel = function() {
this.param = {
error: true,
italic: true
};
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
<style>
.error {
color: red;
}
.italic {
font-style: italic;
}
</style>
</head>
<body>
<span data-bind="css: param">error message</span>
</body>
</html>
- パラメタにオブジェクトを指定すると、フィールド名に対応する CSS クラスが設定される。
- フィールドの値が true (と判定される値)の場合は、その CSS クラスが有効になる。
HTML 側で以下のように指定することもできる。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
<style>
.error {
color: red;
}
.italic {
font-style: italic;
}
</style>
</head>
<body>
<span data-bind="css: {error: isError, italic: isItalic}">error message</span>
</body>
</html>
CSS スタイルを指定する
window.onload = function() {
var ViewModel = function() {
this.param = {
color: 'red',
fontStyle: 'italic'
};
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<span data-bind="style: param">error message</span>
</body>
</html>
-
style
バインディングを使うと、 CSS のスタイルを直接指定することができる。 - パラメタにはオブジェクトを渡し、プロパティ名を CSS のスタイル属性と一致させる。
- スタイル属性名にハイフンが含まれる場合は、そのままだと JavaScript のプロパティ名として使用できないので、 camelCase に置き換えて設定する。
- プロパティの値に、具体的な属性値を指定する。
タグの属性値を設定する
window.onload = function() {
var ViewModel = function() {
this.param = {
href: 'http://www.google.co.jp',
title: 'Google'
};
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<a data-bind="attr: param">link</a>
</body>
</html>
-
attr
バインディングを使うと、タグの属性値を設定できる。 - パラメタにはオブジェクトを渡す。フィールド名に指定したい属性名を設定する。
- 属性名にハイフンが含まれる場合は、
'aaa-bbb'
のようにフィールドを文字列で指定する。
フロー制御
繰り返し処理
window.onload = function() {
var viewModel = {
array: ['hoge', 'fuga', 'piyo']
};
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<ul data-bind="foreach: array">
<li data-bind="text: $data"></li>
</ul>
</body>
</html>
-
foreach
バインディングを使用すると、指定した配列を繰り返し処理しながら DOM を生成することができる。 - 繰り返し処理中の各要素は
$data
で参照できる。
要素の参照に別名を指定する
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<ul data-bind="foreach: {data: array, as: 'element'}">
<li data-bind="text: element"></li>
</ul>
</body>
</html>
- パラメタに
{data: <処理対象のオブジェクト>, as: '<別名>'}
と指定することで、繰り返し中の要素に別名を付けることができる。
現在のインデックスを参照する
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<ul data-bind="foreach: array">
<li>
<span data-bind="text: $index"></span> : <span data-bind="text: $data"></span>
</li>
</ul>
</body>
</html>
-
$index
で現在のインデックスを取得できる。
繰り返しのためのタグを使用しないで foreach を使う
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<ul>
<!-- ko foreach: array -->
<li data-bind="text: $data"></li>
<!-- /ko -->
</ul>
</body>
</html>
- コメントを利用した コンテナレス構文 を使用することで、繰り返しのためのタグを使うこと無く
foreach
を使用することができる。
配列を Observable にする
window.onload = function() {
var viewModel = {
array: ko.observableArray([
'hoge',
'fuga',
'piyo'
])
};
ko.applyBindings(viewModel);
document.getElementById('add').onclick = function() {
viewModel.array.push('add');
};
document.getElementById('remove').onclick = function() {
viewModel.array.pop();
};
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<ul data-bind="foreach: array">
<li data-bind="text: $data"></li>
</ul>
<button id="add">add</button>
<button id="remove">remove</button>
</body>
</html>
↓ add
ボタンをクリック
↓ remove
ボタンをクリック
-
ko.observableArray()
関数で、配列用の Observable オブジェクトを作成できる。 - このオブジェクトを Observable Array と呼ぶ。
Observable Array で使用できるメソッド
基本
- Observable Array には、通常の JavaScript の Array クラスで使用できるものと同じメソッドが用意されている。
- IE8 以前では使用できない
indexOf()
メソッドも、 Observable Array では使用できる。
生の配列を取得する
var array = ko.observableArray([
'hoge',
'fuga',
'piyo'
]);
console.log(array()); //=> ["hoge", "fuga", "piyo"]
- Observable Array を関数として実行すると、生の配列が取得できる。
追加されているメソッド
Observable Array には、以下のメソッドが追加されている。
remove(item)
var array = ko.observableArray([
'hoge',
'fuga',
'hoge'
]);
var removed = array.remove('hoge');
console.log('removed = ' + removed); //=> removed = hoge,hoge
console.log('array = ' + array()); //=> array = fuga
-
remove(<削除したい要素>)
で、該当する全ての要素が削除される。 - 戻り値に、削除された要素が配列で返される。
remove(Function)
var array = ko.observableArray([
'a',
'bb',
'ccc'
]);
var removed = array.remove(function(item) {
return 1 < item.length
});
console.log('removed = ' + removed); //=> removed = bb,ccc
console.log('array = ' + array()); //=> arrary = a
-
remove(Function)
で、各要素ごとに削除するかどうかの判定を行うことができる。 - 関数が
true
を返した場合に、その要素が削除される。
removeAll(Array)
var array = ko.observableArray([
'hoge',
'fuga',
'piyo',
'fuga'
]);
var removed = array.removeAll(['hoge', 'fuga']);
console.log('removed = ' + removed); //=> removed = hoge,fuga,fuga
console.log('array = ' + array()); //=> array = piyo
-
removeAll(Array)
で、引数で渡した配列の各要素に一致する要素が削除される。
removeAll()
var array = ko.observableArray([
'hoge',
'fuga',
'piyo'
]);
var removed = array.removeAll();
console.log('removed = ' + removed); //=> removed = hoge,fuga,piyo,fuga
console.log('array = ' + array()); //=> array =
-
removeAll()
で、全ての要素を削除できる。
DOM の出力を切り替える
window.onload = function() {
var viewModel = {
isTrue: true,
isFalse: false
};
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<span data-bind="if: isTrue">isTrue</span>
<span data-bind="if: isFalse">isFalse</span>
</body>
</html>
-
if
バインディングを使用すると、 DOM の出力を切り替えることができる。 -
visible
バインディングは CSS で非表示にしているだけなのに対して、if
バインディングは DOM を削除するという違いがある。
コンテナレス構文を使用する
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<!-- ko if: isTrue -->
isTrue
<!-- /ko -->
<!-- ko if: isFalse-->
isFalse
<!-- /ko -->
</body>
</html>
条件が偽のときだけ DOM を出力する
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<span data-bind="ifnot: isTrue">isTrue</span>
<span data-bind="ifnot: isFalse">isFalse</span>
</body>
</html>
-
ifnot
バインディングを使用すると、条件式が偽の場合にのみ DOM が出力される。
新しいコンテキストを定義する
window.onload = function() {
var viewModel = {
message: 'root context message',
subContext: {
message: 'sub context message'
}
};
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<span data-bind="text: message"></span>
<div data-bind="with: subContext">
<span data-bind="text: message"></span>
</div>
</body>
</html>
-
with
バインディングを使用すると、新しいコンテキストを定義できる。 - コンテナレス構文で使用することも可能。
フォーム部品にバインド
クリックイベント
window.onload = function() {
var viewModel = {
onClick: function() {
console.log('click!!');
}
};
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<button data-bind="click: onClick">button</button>
</body>
</html>
click!!
-
click
バインディングを使うと、クリックイベントをハンドリングできる。
関数に渡される引数
第一引数には、その場所におけるコンテキストが渡される
window.onload = function() {
var viewModel = {
name: 'root',
onClick: function(obj) {
console.log(obj.name);
},
sub: {
name: 'sub',
onClick: function(obj) {
console.log(obj.name);
}
}
};
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<button data-bind="click: onClick">root</button>
<div data-bind="with: sub">
<button data-bind="click: onClick">sub</button>
</div>
</body>
</html>
root
sub
第二引数にはイベントオブジェクトが渡される
window.onload = function() {
var viewModel = {
onClick: function(obj, event) {
console.log(event.type);
}
};
ko.applyBindings(viewModel);
};
click
任意のイベントにバインドする
window.onload = function() {
var viewModel = {
param: {
mouseover: function() {
console.log('over');
},
mouseout: function() {
console.log('out');
}
}
};
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
<style>
div {
width: 100px;
height: 100px;
background-color: red;
}
</style>
</head>
<body>
<div data-bind="event: param">
</div>
</body>
</html>
over
out
-
event
バインディングを使用すると、任意のイベントに処理をバインドできる。 - パラメタにはオブジェクトを渡す。
- オブジェクトのプロパティ名を、イベントの名前と一致させる。
formのサブミットイベントにバインドする
window.onload = function() {
var viewModel = {
onSubmit: function() {
console.log('submit!!');
}
};
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<form data-bind="submit: onSubmit">
<input type="text" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
submit!!
-
submit
バインディングを使用すると、 form のサブミットに処理をバインドできる。 - デフォルトの submit 処理は実行されない。
- submit を実行したい場合は、コールバック関数が
true
を返すように実装する。
- submit を実行したい場合は、コールバック関数が
フォームの有効・無効を設定する
window.onload = function() {
var viewModel = {
isTrue: true,
isFalse: false
};
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<button data-bind="enable: isTrue">Enable Button</button>
<button data-bind="enable: isFalse">Dnable Button</button>
<br>
<button data-bind="disable: isTrue">Dnable Button</button>
<button data-bind="disable: isFalse">Enable Button</button>
</body>
</html>
-
enable
またはdisable
バインディングを使用すると、フォームの有効・向こうを設定できる。
チェックボックス(ラジオボタン)にバインディングする
チェックボックス
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<input type="checkbox" data-bind="checked: true" />
<input type="checkbox" data-bind="checked: false" />
</body>
</html>
- パラメタが真の場合に、チェックボックスがチェックされる。
配列を使ってチェックのオン・オフを設定する
window.onload = function() {
var viewModel = {
array: ['hoge', 'piyo']
};
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<input type="checkbox" value="hoge" data-bind="checked: array" />
<input type="checkbox" value="fuga" data-bind="checked: array" />
<input type="checkbox" value="piyo" data-bind="checked: array" />
</body>
</html>
- パラメタに配列を指定した場合、 input タグの value で指定している値が配列に含まれる場合に、チェックがオンになる。
ラジオボタン
window.onload = function() {
var viewModel = {
myRadioValue: 'fuga'
};
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<input type="radio" name="myRadio" value="hoge" data-bind="checked: myRadioValue" />
<input type="radio" name="myRadio" value="fuga" data-bind="checked: myRadioValue" />
<input type="radio" name="myRadio" value="piyo" data-bind="checked: myRadioValue" />
</body>
</html>
- パラメタの値と value 属性で指定した値が同じ場合に、ラジオボタンのチェックがオンになる。
セレクトタグにバインディングする
基本
window.onload = function() {
var viewModel = {
array: ['hoge', 'fuga', 'piyo']
};
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<select data-bind="options: array"></select>
</body>
</html>
-
options
バインディングを使うと、 select タグの中身(option タグ)を生成することができる。 - パラメタに配列を渡すと、各要素がそのまま option タグの value とラベルに使用される。
初期選択値を指定する
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<select data-bind="options: array, value: 'fuga'"></select>
</body>
</html>
- value で初期選択値を指定できる。
ラベルと値を指定する
window.onload = function() {
var viewModel = {
array: [{
id: 11,
name: 'HOGE'
}, {
id: 22,
name: 'FUGA'
}, {
id: 33,
name: 'PIYO'
}]
};
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<select data-bind="options: array,
optionsValue: 'id',
optionsText: 'name'"></select>
</body>
</html>
-
options
パラメタに渡す配列の各要素をオブジェクトにする。 -
optionsValue
パラメタで、value
属性に設定するプロパティ名を指定する。 -
optionsText
パラメタで、ラベルに設定するプロパティ名を指定する。
ラベルと値に関数の処理結果を渡す
window.onload = function() {
var viewModel = {
array: [{
id: 11,
name: 'HOGE'
}, {
id: 22,
name: 'FUGA'
}, {
id: 33,
name: 'PIYO'
}],
toId: function(item) {
return 'id_' + item.id;
},
toLabel: function(item) {
return 'Label : ' + item.name;
}
};
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<select data-bind="options: array,
optionsValue: toId,
optionsText: toLabel"></select>
</body>
</html>
-
optionsValue
とoptionsLabel
に関数を渡す。 - 関数は
options
パラメタで指定した配列をイテレートするのに使用され、引数に配列の要素が順次渡される。 - 関数の戻り値が、それぞれ
value
とラベルに使用される。
複数選択可能な場合の初期値設定
window.onload = function() {
var viewModel = {
array: ['hoge', 'fuga', 'piyo'],
selectedArray: ['hoge', 'piyo']
};
ko.applyBindings(viewModel);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<select size="3" multiple
data-bind="options: array,
selectedOptions: selectedArray"></select>
</body>
</html>
- 複数選択可な select ボックスに初期値を設定する場合は、
selectedOptions
パラメタを指定する。 -
selectedOptions
パラメタには、選択対象にしたい値を配列に詰めて渡す。
テンプレート
基本
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<div data-bind="template: {name: 'myTemplate', data: myModel}">
</div>
<script type="text/html" id="myTemplate">
<i data-bind="text: message"></i>
</script>
</body>
</html>
window.onload = function() {
var viewModel = {
myModel: {
message: 'Hello Template!!'
}
};
ko.applyBindings(viewModel);
};
-
template
バインディングを使うと、テンプレートを使用したタグの埋め込みができる。 - テンプレートは、
<script type="text/html">
タグを使って定義する。 -
name
パラメタには、テンプレートの<script>
タグで定義したid
属性を指定する。 -
data
パラメタには、テンプレート内で参照できるモデルを指定する。
条件によって表示・非表示を切り替える
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<div data-bind="template: {name: 'myTemplate', if: false}">
</div>
<hr>
<div data-bind="template: {name: 'myTemplate', if: true}">
</div>
<script type="text/html" id="myTemplate">
<h3>Template Block</h3>
</script>
</body>
</html>
-
if
パラメタを指定すると、 true のときだけテンプレートが出力されるようになる。
テンプレートを繰り返し出力する
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<ul data-bind="template: {name: 'myTemplate', foreach: array}">
</ul>
<script type="text/html" id="myTemplate">
<li data-bind="text: message"></li>
</script>
</body>
</html>
window.onload = function() {
var viewModel = {
array: [
{message: 'hoge'},
{message: 'fuga'},
{message: 'piyo'}
]
};
ko.applyBindings(viewModel);
};
-
foreach
パラメタに配列を指定することで、その要素数だけテンプレートが繰り返し処理される。
テンプレートがネストされているときに、親テンプレートの値を参照する
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<div data-bind="template: {name: 'parentTemplate', data: parentModel, as: 'parent'}">
</div>
<script type="text/html" id="parentTemplate">
<div data-bind="template: {name: 'childTemplate', data: childModel}">
</div>
</script>
<script type="text/html" id="childTemplate">
parent.name = <span data-bind="text: parent.name"></span><br>
child.name = <span data-bind="text: name"></span>
</script>
</body>
</html>
window.onload = function() {
var viewModel = {
parentModel: {
name: 'ParentName',
childModel: {
name: 'ChildName'
}
}
};
ko.applyBindings(viewModel);
};
-
as
パラメタを使うと、テンプレートに渡されたモデルを参照するための名前が指定できる。 - テンプレートが1階層までしかない場合は必要ないが、テンプレートが入れ子になっていて、子のテンプレートが親テンプレートの値を参照したい場合は
as
で指定が必要になる。
テンプレートが DOM に反映された直後に処理を挟む
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<div data-bind="template: {name: 'myTemplate', afterRender: onAfterRender}"></div>
<script type="text/html" id="myTemplate">
<h2 id="msg"></h2>
</script>
</body>
</html>
window.onload = function() {
var viewModel = {
onAfterRender: function() {
document.getElementById('msg').innerText = 'after render';
}
};
ko.applyBindings(viewModel);
};
-
afterRender
オプションを指定すると、テンプレートが DOM に反映された直後に処理を挟むことができる。
1つのタグに複数のバインディングを適用する
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<span data-bind="text: 'Hello Knockout.js', style: {color: 'blue'}"></span>
</body>
</html>
-
,
カンマ区切りで複数のバインディングを適用できる。
バインディングを自作する
基本
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<div data-bind="myBinding"></div>
</body>
</html>
window.onload = function() {
ko.bindingHandlers.myBinding = {
init: function(element, valueAccessor, allBindings) {
element.innerText = 'Hello Custom Binding!!';
}
};
ko.applyBindings();
};
-
ko.bindingHandlers
にプロパティを追加することで、自作のバインディングを定義することができる。 - バインディングが実行されるときに、
init()
メソッドが実行されるので、そこで処理を実行する。 -
element
に、カスタムバインディングが適用されている対象の DOM オブジェクトが渡される。
パラメータの値を取得する
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<div data-bind="myBinding: 101"></div>
</body>
</html>
window.onload = function() {
ko.bindingHandlers.myBinding = {
init: function(element, valueAccessor, allBindings) {
var param = valueAccessor();
element.innerText = 'param = ' + param;
}
};
ko.applyBindings();
};
-
valueAccessor
を引数なしの関数として実行すると、パラメータに渡された値を取得できる。
パラメータが Observable だった場合
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<div data-bind="myBinding: myModel"></div>
</body>
</html>
window.onload = function() {
ko.bindingHandlers.myBinding = {
init: function(element, valueAccessor, allBindings) {
var param = valueAccessor();
element.innerText = 'param = ' + param;
}
};
var viewModel = {
myModel: ko.observable(201)
};
ko.applyBindings(viewModel);
};
パラメータに渡された値が Observable だった場合、valueAccessor()
で取得しただけでは生の値を取得できない。
しかし、取得した値が Observable かどうかをいちいち判定するのは面倒。
valueAccessor()
の戻り値が Observable かどうかにかかわらず生の値を取得したい、という場合は ko.unwarp()
関数を使う。
window.onload = function() {
ko.bindingHandlers.myBinding = {
init: function(element, valueAccessor, allBindings) {
var param = valueAccessor();
var msg = 'observableValue=' + ko.unwrap(param.observableValue)
+ ', standardValue=' + ko.unwrap(param.standardValue);
element.innerText = msg;
}
};
var viewModel = {
myModel: {
observableValue: ko.observable(201),
standardValue: 301
}
};
ko.applyBindings(viewModel);
};
-
ko.unwrap()
関数に値を渡すと、 Observable ならその生の値を、もともと生の値ならその値をそのまま返してくれる。 - なので、パラメータに指定された値が Observable なのかどうかを考慮しなくて済むようになる。
同じタグに指定されている別のバインディングを取得する
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<div data-bind="myBinding, text: 'text binding'"></div>
</body>
</html>
window.onload = function() {
ko.bindingHandlers.myBinding = {
init: function(element, valueAccessor, allBindings) {
element.innerText = allBindings.get('text');
}
};
ko.applyBindings();
};
-
allBidings.get('<取得したいバインディングの名前>')
で、他に指定されているバインディングのパラメータを取得できる。 - バインディングが指定されていない場合は、
undefined
が返される。 - そもそもバインディングが適用されているかを知りたい場合は、
allBindings.has('<名前>')
で確認できる。
パラメータに指定された Observable の値が変更されたときに処理を実行する
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="knockout-3.2.0.js"></script>
<script src="sample.js"></script>
</head>
<body>
<div data-bind="myBinding: message"></div>
<input type="text" data-bind="value: message" />
</body>
</html>
window.onload = function() {
ko.bindingHandlers.myBinding = {
init: function(element, valueAccessor, allBindings) {
element.innerText = ko.unwrap(valueAccessor());
},
update: function(element, valueAccessor, allBindings) {
element.innerText = ko.unwrap(valueAccessor());
}
};
var viewModel = {
message: ko.observable('hello custom binding')
};
ko.applyBindings(viewModel);
};
↓テキストボックスの値を変更する
- パラメータが Observable の場合、値が変更されると
update()
メソッドがコールバックされる。