technoshop

杉並区和泉のソフトウェアハウス、株式会社テラソフトの技術ブログです。主に.NET MVCとKnockoutJSの情報をまとめます。

.Net MVC4 で KnockoutJS ~【基礎編4】成績表を作ってみよう Part2

ザクです。

前回はko.utils.arrayForEachとko.computedを組み合わせてエクセル関数的なself.totalcreditsという変数を作ってみました。全単位の合計は計算して表示することができましたが、肝心の成績表の部分がモックのままです。ここを仕上げてみたいと思います。

ko.utils.arrayFilterで条件で配列を取り出す

ko.utilsはKnockoutの便利なユーティリティです。前回はarrayForEachを使ってObservableArrayに対してループを回してみました。今回使うのはko.utils.arrayFilterです。これはObservableArrayに対して条件で絞込みをします。ちょっと変わった書き方するので、慣れが必要です。

グレードごとに取得した単位の合計を求めるのに使ってみます。

var counter = ko.utils.arrayFilter(self.Enrollments(), function (el) {
    return el.Grade() === 0;
});

こんな風に書きます。結果に条件に引っかかったObservableArrayの中身がオブジェクトの配列で帰ってきますので、入れ物の変数を用意してやります。カウンターっぽく使うのでcounterとしました。中身は条件に合致したEnrollmentのオブジェクトです。functionの後の括弧の中にファンクションの中で使うオブジェクトの変数を決めてやり、returnの後が「条件節」になっています。したがって、EnrollmentオブジェクトのGradeがゼロ(0)か見ています。ここでゼロと確認しているのは、MVC4側のGradeがEnumでAがintのゼロになっているからです。

これを応用して、各グレードの単位数の合計を計算します。ko.utils.arrayFilterを使って、生徒がA(やBやC)を取った授業の単位数を積算していきます。こんな感じのコードになりました。

        // Counters for each grade
        self.gradeA = ko.computed(function () {
            var counter = ko.utils.arrayFilter(self.Enrollments(), function (el) {
                return el.Grade() === 0;
            });
            var total = 0;
            ko.utils.arrayForEach(counter, function (co) {
                var value = co.Credits();
                if (!isNaN(value)) {
                    total += value;
                }
            });
            return total;
        });
        self.gradeB = ko.computed(function () {
            var counter = ko.utils.arrayFilter(self.Enrollments(), function (el) {
                return el.Grade() === 1;
            });
            var total = 0;
            ko.utils.arrayForEach(counter, function (co) {
                var value = co.Credits();
                if (!isNaN(value)) {
                    total += value;
                }
            });
            return total;
        });
        self.gradeC = ko.computed(function () {
            var counter = ko.utils.arrayFilter(self.Enrollments(), function (el) {
                return el.Grade() === 2;
            });
            var total = 0;
            ko.utils.arrayForEach(counter, function (co) {
                var value = co.Credits();
                if (!isNaN(value)) {
                    total += value;
                }
            });
            return total;
        });

なんか冗長ですが、ビューに出すときにグレードごとに計算されていたほうが扱いやすいのでこのまま行きます。いま作ったko.computed変数がちゃんと計算しているか確認するには、Context Debuggerを使ってもいいですし、Viewに出力してしまってもいいです。もう、どうやるかわかりますよね?

ついでなので、GPAも計算して横に出してみましょうか?せっかくなので、これは演習にしてみましょう。GPAを計算するko.computedを実装してみてください。GPAの計算方法は以下のリンク先の通りです。


GPAの計算

ビューはこんな感じにしておきましょうか。(Bootstrapマジ便利っすね!)

<h2>Student Grades</h2>

<table class="table table-bordered">
    <tr>
        <th rowspan="2">
            Last Name
        </th>
        <th rowspan="2">
            First Name
        </th>
        <th class="text-center" rowspan="2">
            Credits
        </th>
        <th class="text-center" colspan="3">
            Grade
        </th>
        <th class="text-center" rowspan="2">
            GPA
        </th>
    </tr>
    <tr>
        <th class="text-center">A</th>
        <th class="text-center">B</th>
        <th class="text-center">C</th>
    </tr>
    <!-- ko foreach: Students -->
    <tr>
        <td><span data-bind="text: LastName"></span></td>
        <td><span data-bind="text: FirstMidName"></span></td>
        <td class="text-center"><span data-bind="text: totalcredits"></span></td>
        <td class="text-center"><span data-bind="text: gradeA"></span></td>
        <td class="text-center"><span data-bind="text: gradeB"></span></td>
        <td class="text-center"><span data-bind="text: gradeC"></span></td>
        <td class="text-center"><span data-bind="text: gpa"></span></td>
    </tr>
    <!-- /ko -->
</table>

ザクの実装ではこんな結果になりました!

f:id:technoshop:20141006155500j:plain