KO範例8 - if及with的應用

假想以下情境,ViewModel有個players屬性,為一ko.observableArray,其中的元素為player,具有name及bestRecord兩個屬性,其中bestRecord預期會再包含date及score屬性。

在網頁上,打算用foreach將每個player以<li>方式呈現,

<ul data-bind="foreach: players">
    <li>
        <span data-bind="text: name"></span>
        <span data-bind="visible: bestRecord">
            (最佳成績:
                <span data-bind="text: bestRecord().score"></span>
                於
                <span data-bind="text: bestRecord().date"></span>)
        </span>
    </li>
</ul>

由於player不一定有bestRecord,所以我們利用範例7介紹的visible,在bestRecord有資料時才顯示其date及score。完整程式碼如下:

<!DOCTYPE html>
<html>
<head>
    <title>Lab 8 - with應用(問題展示)</title>
    <script src="../Scripts/jquery-1.7.2.js"></script>
    <script src="../Scripts/knockout-2.1.0.debug.js"></script>
    <script>
        function player(name) {
            var self = this;
            self.name = ko.observable(name);
            self.bestRecord = ko.observable();
            self.setBestRecord = function (d, s) {
                self.bestRecord({
                    date: d, score: s
                });
            };
        }
 
        function MyViewModel() {
            var self = this;
            self.players = ko.observableArray();
        }
 
        $(function () {
            var vm = new MyViewModel();
            //第一筆資料有最佳成績(含日期及分數)
            var p1 = new player("Darkthread");
            p1.setBestRecord("2012-06-01", 65535);
            vm.players.push(p1);
            //第二筆資料無最佳成績
            var p2 = new player("Jeffrey");
            vm.players.push(p2);
 
            ko.applyBindings(vm);
        });
    </script>
    <style>
    span { margin: 5px; }
    </style>
</head>
<body>
    <ul data-bind="foreach: players">
        <li>
            <span data-bind="text: name"></span>
            <!-- 
                原本想法是沒有bestRecord時隱藏<span>區塊,但是其中的內容
                還是會被解析,由於bestRecord()無內容,呼叫.score時會出錯
            -->
            <span data-bind="visible: bestRecord">
                (最佳成績: 
                    <span data-bind="text: bestRecord().score"></span>
                    <span data-bind="text: bestRecord().date"></span>)
            </span>
        </li>
    
    </ul>
</body>
</html>

但以上程式是有問題的,實測時會產生如下錯誤: 線上展示(注意: 該網頁會引發JavaScript錯誤)

原來,雖然我們用visible控制在bestRecord無值時不要進一步顯示date及score,但是visible只控制HTML Style層次的display: none,KO仍會繼續解析其下內容,形成bestRecord()明明是null,卻試著去取score, date屬性的情況而發生錯誤!

要解決這個問題,我們可以改用 if,if 跟 visible 最大的不同,在於 if 條件式不成立時,KO會略過該HTML容器內子元素的data-bind不處理,便不會產生null還硬要取屬性的錯誤。改用 if 之後程式如下: 線上展示

<ul data-bind="foreach: players">
    <li>
        <span data-bind="text: name"></span>
        <!-- 使用if判斷,有最佳成績時才處理 -->
        <span data-bind="if: bestRecord">
            (最佳成績:
                <span data-bind="text: bestRecord().score"></span>
                於
                <span data-bind="text: bestRecord().date"></span>)
        </span>
    </li>
</ul>

除了 if,還有個 with 可實現相似效果,而且更方便的一點是: 當with繫結到指定物件,容器內子元素預設data-bind的對象就會變成該物件。於是先前的text: bestRecord().score,可以簡寫成text: score,更簡潔方便。應用with,程式改寫如下: 線上展示

<ul data-bind="foreach: players">
    <li>
        <span data-bind="text: name">X</span>
        <!--
            使用with有if的效果,bestRecord()有內容時,
            span的內容才會出現在DOM中,而且Binding Context會
            切成bestRecord,所以bestRecord().score直接寫成score即可
        -->
        <span data-bind="with: bestRecord">
            (最佳成績:
                <span data-bind="text: score"></span>
                於
                <span data-bind="text: date"></span>)
        </span>
    </li>
</ul>

[KO系列]
http://www.darkthread.net/kolab/labs/default.aspx?m=post
歡迎推文分享:
Published 13 September 2012 06:18 AM 由 Jeffrey
Filed under:
Views: 10,416



意見

# Evo.vivi said on 13 September, 2012 01:08 AM

Hi 黑大,

以此例而言, 我若想要在firebug console上看到var vm = new MyViewModel();的這個vm物件, 請要要怎麼用?

# Jeffrey said on 13 September, 2012 05:25 AM

to Evo.vivi,

有兩個做法,第一種是把vm變成全域變數,例如: 改成window.vm = new MyViewModel();,但要留意全域變數的副作用;第二種做法是利用KO提供的方法,ko.dataFor(element)找到element繫結的ViewModel物件,在本例中ko.dataFor($("ul")[0]).players().length可以得到2。

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<September 2012>
SunMonTueWedThuFriSat
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456
 
RSS
創用 CC 授權條款
【廣告】
twMVC

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication