SourceChord

C#とXAML好きなプログラマの備忘録。最近はWPF系の話題が中心です。

Knockout.jsで複数選択可能なテーブル

Knockout.jsなテーブルネタもう一個。
複数選択可能にしてみました。

f:id:minami_SC:20150522015415p:plain:w300

選択中の項目をKnockoutObservableArray型で保持しておき、
選択中のリストに含まれているかどうかチェックして、列の要素(tr)の属性を変えています。

今回もとりあえずコードだけφ(..)メモメモ

index.html
<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Selectable Table Sample</title>
    <link rel="stylesheet" href="app.css" type="text/css" />
    <script src="Scripts/knockout-3.3.0.js"></script>
    <script src="app.js"></script>
</head>
<body>
    <h2>複数選択なテーブルのサンプル</h2>

    <span>選択項目:</span>
    <span data-bind="text: selected().name"></span>
    <br />

    <table class="selectableTable">
        <thead>
            <tr>
                <th>名前</th>
                <th>年齢</th>
                <th>メモ</th>
            </tr>
        </thead>
        <tbody data-bind="foreach: list">
            <tr data-bind="click: $parent.onClicked, attr: {'selected': $parent.checkSelected($data)}">
                <td data-bind="text: name"></td>
                <td data-bind="text: age"></td>
                <td data-bind="text: memo"></td>
            </tr>
        </tbody>
    </table>
</body>
</html>
app.ts
/// <reference path="scripts/typings/knockout/knockout.d.ts" />

class Person {
    constructor(public name: string,
                public age: number,
                public memo: string) {
    }
}

class AppViewModel {
    public list: KnockoutObservableArray<Person>;
    public selected: KnockoutObservableArray<Person>;

    constructor() {
        this.list = ko.observableArray<Person>();
        this.selected = ko.observableArray<Person>();

        for (var i = 0; i < 10; i++) {
            this.list.push(new Person("hoge" + i + "さん", i, "..."));
        }

        // 最初の要素を選択しておく
        this.selected.push(this.list()[0]);
    }


    public onClicked = (data) => {
        var current = this.checkSelected(data);
        if (current) {
            this.selected.remove(data);
        } else {
            this.selected.push(data);
        }
    }

    // 引数で渡された要素が、現在選択中かどうか判定するメソッド
    public checkSelected = (data) => {
        var isFound = ko.utils.arrayFirst(this.selected(),(item) => item === data) !== null;
        return isFound;
    }
}

window.onload = () => {
    var viewmodel = new AppViewModel();
    ko.applyBindings(viewmodel);
};
app.css
body {
    font-family: 'Segoe UI', sans-serif;
}

span {
    font-style: italic;
}


.selectableTable {
    width: 100%;
    border-collapse: collapse;
}

    .selectableTable th {
        width: 33%;
        padding: 4px;
        text-align: center;
        vertical-align: top;
        color: #333;
        background-color: silver;
        border: 1px solid #b9b9b9;
    }

    .selectableTable tr {
    }

        .selectableTable tr:nth-child(odd) {
            background: whitesmoke;
        }

    .selectableTable td {
        padding: 3px;
        border: 1px solid darkgray;
    }

    .selectableTable tbody tr:hover {
        background: #E5E5E5;
        cursor: pointer;
    }

    .selectableTable tr[selected] {
        background: #E0E8FF;
        font-weight: bold;
    }