完敗だぜ!knockoutでノックアウト – バインディング編

みなさんこんにちは。江口です。
 
前回は Observable編2 でした。今回は KnockoutJS で提供されているバインディングを簡単にひと通り紹介します。
KnockoutJSでは、データとUIをより簡単に結びつけるためにバインディングの機能を提供しています。標準で22 種類の強力なバインディングが提供されているため、データの状態をさまざまな方法でUI上に表現する事ができるようになっています。 

テキストと外観の制御(Controlling text and appearance)

テキストや要素のスタイル、属性の制御に利用できるバインディングは以下の6種類が提供されています。

visible

要素の表示・非表示の切り替えに使用できるバインディングです。
パラメータの値が true (または 0, null, undefined以外)の場合は要素が表示、それ以外の場合は非表示にさせることができます。
 
<span data-bind="visible: messageVisible">Hello</span>
    
<script type="text/javascript">
    var vm = {
        messageVisible: ko.observable(true)
    };

    ko.applyBindings(vm);
</script>

 text

データをテキストとして表示するのに使用できるバインディングです。
パラメータの値に null または undefined を指定した場合のテキストは空文字になります。
<span data-bind="text: message"></span>

<script type="text/javascript">
    var vm = {
        message: ko.observable('KnockoutJS')
    };

    ko.applyBindings(vm);
</script>

 バインディングにspanタグなどの要素を使用したくない場合は、コメント要素にバインディングを使用することも出来ます。

<!--ko text: message--><!--/ko-->

 html

データをDOM要素として設定するのに使用できるバインディングです。
パラメータに指定された値をinnerHtmlの値に設定します。
<div data-bind="html: content"></div>

<script type="text/javascript">
    var vm = {
        content: ko.observable('<b>KnockoutJS</b>')
    };

    ko.applyBindings(vm);
</script>

 css

要素のクラス属性を制御するのに使用できるバインディングです。
パラメータの値が true (または 0, null, undefined以外)の場合に要素の class に適用されます。
<span data-bind="css: {overDue: overDue}">Due Date</span>

<script type="text/javascript">
    var vm = {
        overDue: ko.observable(true)
    };

    ko.applyBindings(vm);
</script>

 一つの要素に複数のクラスを設定することも出来ます。

<span data-bind="css: {overDue: overDue, selected: selected}">Due Date</span>

 style

要素にスタイル属性を追加・削除するのに使用できるバインディングです。
スタイル名と設定する値を指定すると、その要素に直接スタイルが適用されます。
<span data-bind="style: { color : color }">Due Date</span>

<script type="text/javascript">
    var vm = {
        color: ko.observable('red')
    };

    ko.applyBindings(vm);
</script>
スタイル名の文字には”-“を使用できないので、キャメルケースで指定する必要があります。
 
font-weight -> fontWeight

 attr

要素に任意の属性を追加・削除するのに使用できるバインディングです。
属性名と設定する値を指定すると、その要素の属性に設定されます。
<img src="loading.gif" data-bind="attr: { src: icon }" />

<script type="text/javascript">
    var vm = {
        icon: ko.observable('complete.png')
    };

    ko.applyBindings(vm);
</script>

フロー制御(control flow) 

 DOM 構造の制御に利用できるバインディングは以下の4種類が提供されています。

foreach

要素を繰り返しコピーするのに使用できるバインディングです。
値に指定した配列もしくはobservableArrayの長さ分だけ、バインディングを設定した要素の子孫が繰り返し生成されます。foreach バインディング内では $index という特別なプロパティで、現在のインデックスの値を取り出すことが出来ます。
<table>
    <tbody data-bind="foreach: issues">
    <tr>
        <td data-bind="text: $index"></td>
        <td data-bind="text: summary"></td>
        <td data-bind="text: status"></td>
    </tr>
    </tbody>
</table>

<script type="text/javascript">
    var vm = {
        issues:[
            { summary: 'KnockoutJS', status: 'In Progress'},
            { summary: 'Backlog', status: 'Resolved'}
        ]
    };

    ko.applyBindings(vm);
</script>

 text バインディングと同じく、コメント要素にバインディングを使用することも出来ます。

<!--ko foreach: issues-->
<span data-bind="text: summary"></span>
<!--/ko-->

 if / ifnot

要素の追加・削除に使用できるバインディングです。
パラメータの値が true (または 0, null, undefined以外)の場合は要素が表示、それ以外の場合は非表示にさせることができます。
visible バインディングとは異なり、バインディングを設定した要素の子孫要素が操作の対象になります。また、DOMツリーから子孫要素自体が取り除かれます。
<div data-bind="if: progress">
    <img src="loading.gif" alt="loading"/>
</div>

<script type="text/javascript">
    var vm = {
        progress: ko.observable(true)
    };

    ko.applyBindings(vm);
</script>

 コメント要素にバインディングを使用することも出来ます。

<!--ko if: progress-->
<img src="loading.gif" alt="loading" />
<!--/ko-->

with

バインディングコンテキストの制御に使用できるバインディングです。
foreach バインディングや template バインディングが暗黙的に生成するバインディングコンテキストですが、それを任意の要素を指定して生成できるバインディングです。ViewModel が大きい場合に、内部を分割してスコープを小さくすることで可読性やメンテナンス性を上げることが出来ます。
<span data-bind="text: title"></span>

<div data-bind="with:issue">
    <span data-bind="text: summary"></span>
    <span data-bind="text: status"></span>
</div>
<div data-bind="with: user">
    <span data-bind="text: name"></span>
    <span data-bind="text: age"></span>
</div>

<script type="text/javascript">
    var vm = {
        title: 'Backlog Blog',
        issue: { summary: 'KnockoutJS', status: 'In Progress' },
        user: { name: 'eguchi', age: 26 }
    };

    ko.applyBindings(vm);
</script>

 上の例で with バインディングを使用しなかった場合は以下の様なコードになります。

<span data-bind="text: title"></span>
<div>
    <span data-bind="text: issue.summary"></span>
    <span data-bind="text: issue.status"></span>
</div>
<div>
    <span data-bind="text: user.name"></span>
    <span data-bind="text: user.age"></span>
</div>

フォーム要素(Working with form fields) 

 input や select などのフォーム要素の制御や、マウスクリックを始めとしたイベントへのイベントハンドラの設定に利用できるバインディングは以下の11種類が提供されています。

click

onClick イベントのイベントハンドラを設定できるバインディングです。
指定した関数が、クリックイベントの発生時に呼び出されます。
<span data-bind="click: showAlert">Alert</span>

<script type="text/javascript">
    var vm = {
        showAlert: function () {alert('KnockoutJS')}
    };

    ko.applyBindings(vm);
</script>

 foreach バインディング内で click バインディングや event バインディングを使用した場合、関数の第一引数に foreach の配列内の対応するオブジェクトが渡されます。

<table>
    <tbody data-bind="foreach: issues">
    <tr data-bind="click: $parent.handleClick">
        <td data-bind="text: $index">
        <td data-bind="text: summary"></td>
        <td data-bind="text: status"></td>
    </tr>
    </tbody>
</table>

<script type="text/javascript">
    var vm = {
        issues:[
            { summary: 'KnockoutJS', status: 'In Progress'},
            { summary: 'Backlog', status: 'Resolved'}
        ]
        ,handleClick: function(data){
            alert(data.summary);
        }
    };

    ko.applyBindings(vm);
</script>

 clickBubble を設定すると、イベント伝播を止めることが出来ます。

<span data-bind="click: showAlert, clickBubble: false">Alert<span>

event

任意のイベントのイベントハンドラを設定できるバインディングです。
指定した関数が、イベントの発生時に呼び出されます。
<span data-bind="event: { mouseover: showAlert }">Alert</span>

<script type="text/javascript">
    var vm = {
        showAlert: function () {alert('KnockoutJS')}
    };

    ko.applyBindings(vm);
</script>

 イベント名 + ‘Bubble’ を設定すると、イベント伝播を止めることが出来ます。

 <span data-bind="event: { mouseover: showAlert }, mouseoverBubble: false">Alert<span>

 submit

onsubmit イベントのイベントハンドラを設定できるバインディングです。
指定した関数が、onsubmit イベントの発生時に呼び出されます。
<form data-bind="submit: post">
    <input data-bind="value: message"/>
    <button type="submit">Submit</button>
</form>

 enable / disable

要素の disabled 属性の制御できるバインディングです。
input タグ、select タグ、textarea タグに設定することが出来ます。enable バインディングはパラメータの値が true (または 0, null, undefined以外)の場合はユーザが値を変更可能な状態になり、それ以外の場合は変更不可能にさせることができます。disable バインディングはその逆です。
<input data-bind="enable: canInput"/>
<script type="text/javascript">
    var vm = {
        canInput: ko.observable(false)
    };

    ko.applyBindings(vm);
</script>

value

要素の value 属性の制御できるバインディングです。
input タグ、select タグ、textarea タグに設定することが出来ます。チェックボックスもしくはラジオボタンには checked バインディングを使用します。
value バインディングは双方向にバインディングを行うため、UI上の値が変更されると ViewModel の値が observable であれば自動的に更新されます。
<input data-bind="value: message"/>

<script type="text/javascript">
    var vm = {
        message: ko.observable('KnockoutJS')
    };

    ko.applyBindings(vm);
</script>

hasFocus

要素のフォーカスの制御できるバインディングです。
input タグなどのフォーカスを設定できる要素に設定することが出来ます。
hasFocus バインディングも双方向にバインディングを行うため、UI上でフォーカスが設定されると ViewModel の値が observable であれば自動的に更新されます。
<input data-bind="hasFocus: editing"/>

<script type="text/javascript">
    var vm = {
        editing: ko.observable(true)
    };

    ko.applyBindings(vm);
</script>

checked

チェックボックス/ラジオボタンの状態の制御できるバインディングです。
双方向にバインディングを行うため、UI上で状態が変更されると ViewModel の値が observable であれば自動的に更新されます。
<input type="checkbox" data-bind="checked: value"/>

<script type="text/javascript">
    var vm = {
        value: ko.observable(true)
    };

    ko.applyBindings(vm);
</script>

options

select 要素の選択肢の制御できるバインディングです。
指定した配列または ObservableArray 内の要素が選択肢として表示されます。 
<select data-bind="options: itemList"></select>

<script type="text/javascript">
    var vm = {
        itemList: ['松','竹','梅','桃','桑','桐']
    };

    ko.applyBindings(vm);
</script>

selectedOptions

select 要素の選択項目の設定・取得ができるバインディングです。
双方向にバインディングを行うため、UI上で状態が変更されると ViewModel の値が observable であれば自動的に更新されます。
<select data-bind="options: itemList, selectedOptions: selectedItem"></select>
<span data-bind="text: selectedItem"></span>

<script type="text/javascript">
    var vm = {
        itemList: ['松','竹','梅','桃','桑','桐'],
        selectedItem: ko.observableArray(['梅'])
    };

    ko.applyBindings(vm);
</script>

uniqueName

要素にユニークな name 属性を設定できるバインディングです。

テンプレート(Rendering templates) 

 テンプレートの定義・描画に利用できるバインディングとして template バインディングが提供されています。

パラメータで指定された名前のテンプレートに、データをバインドしてDOMツリーを追加します。テンプレートの定義は script タグ内に定義し、id 属性でテンプレート名を設定します。

<div data-bind="template: { name: 'issue-template', data: issue }"></div>

<script type="text/html" id="issue-template">
    <p>
        <span data-bind="text: summary"></span>
        <span data-bind="text: status"></span>
    </p>
</script>

<script type="text/javascript">
    var vm = {
        issue: {
            summary: 'KnockoutJS',
            status: 'In Progress'
        }
    };

    ko.applyBindings(vm);
</script>

 データに配列または observableArray を使用する場合は、data ではなく foreach でデータを指定します。

<div data-bind="template: { name: 'issueTemplate', foreach: issues }">

また、テンプレートは observable な値や関数を name に設定することで、動的に変更することが出来ます。 

<div data-bind="template: { name: templateName, data: issue }"></div>
<span data-bind="click: changeTemplate">change</span>

<script type="text/html" id="issue-template">
    <p>
        <span data-bind="text: summary"></span>
        <span data-bind="text: status"></span>
    </p>
</script>

<script type="text/html" id="issue-template2">
    <ul>
        <li data-bind="text: summary"></li>
        <li data-bind="text: status"></li>
    </ul>
</script>

<script type="text/javascript">
    var vm = function () {
        var self = this;
        self.templateName = ko.observable('issue-template');
        self.issue = {
            summary: 'KnockoutJS',
            status: 'In Progress'
        };
        self.changeTemplate = function(){
            self.templateName('issue-template2');
        }
    };

    ko.applyBindings(new vm());
</script>

name に関数を設定した場合は、データの内容に応じてテンプレートを切り替えるといったようなことが出来ます。

<div data-bind="template: { name: templateName, data: issue }"></div>

<script type="text/html" id="issue-template">
    <p>
        <span data-bind="text: summary"></span>
        <span data-bind="text: status"></span>
    </p>
</script>

<script type="text/html" id="issue-template2">
    <ul>
        <li data-bind="text: summary"></li>
        <li data-bind="text: status"></li>
    </ul>
</script>

<script type="text/javascript">
    var vm = function () {
        var self = this;
        self.templateName = function (data) {
            return data.status === 'In Progress' ? 'issue-template2' : 'issue-template';
        };
        self.issue = {
            summary: 'KnockoutJS',
            status: 'In Progress'
        };
    };

    ko.applyBindings(new vm());
</script> 
 以上、簡単にでしたが、KnockoutJS で提供されているバインディングの紹介でした。
 
 

より良いチームワークを生み出す

チームの創造力を高めるコラボレーションツール

製品をみる