範例4使用了totalScore ko.computed函數即時加總全部使用者的積分,經實實測,新增或移除資料時積分總和會立即改變。如果是修改某一筆使用者績分呢?

$("#btnChgScore").click(function () {
     vm.users()[0].score = 9999;
});

我們加入一個按鈕模擬修改積分的情境,程式先用vm.users()傳回UserViewModel物件陣列(因為users是ko.observableArray,當成函數呼叫才會傳回JavaScript Array形式的資料),取出第0筆,將其score改為9999。

來看線上展示:

咦? 按了沒反應? 是的,前述做法有個問題,如果期望KO能即時感應屬性變化,UserViewModel的score就必須用ko.observable()而非單純JavaScript物件屬性,所以程式需稍作修改:

function UserViewModel(id, name, score) {
    var self = this;
    self.id = id;
    self.name = name;
    //改為observalbe
    self.score = ko.observable(score);
}

$("#btnChgScore").click(function () {
    //改用score()設定內容
    vm.users()[0].score(9999);
});

提醒: ko.observable型屬性要設定新值時,要透過函數方式呼叫,不要呆呆地直接指定。(剛開始用KO時,我就常幹這種傻事)

修正過的版本,就可以正常運作囉~~

完整程式碼如下:

<!DOCTYPE html>
 
<html>
<head>
    <title>Lab 5 - 即時反應陣列物件的屬性變化</title>
    <script src="../Scripts/jquery-1.7.2.js"></script>
    <script src="../Scripts/knockout-2.1.0.debug.js"></script>
    <script>
        //很簡單的User資料物件
        function UserViewModel(id, name, score) {
            var self = this;
            self.id = id;
            self.name = name;
            //改為observalbe
            self.score = ko.observable(score);
        }
 
        function MyViewModel() {
            var self = this;
            self.users = ko.observableArray();
            //移除User,輸入參數為user物件
            //foreach產生的元素,click事件時會帶入該元素所繫結的資料物件
            self.removeUser = function(user) {
                self.users.remove(user);
            }
            //分數加總,透過神奇的Dendency Tracking功能
            //一旦有任何User分數更動,它就會自動更新
            self.totalScore = ko.computed(function () {
                var total = 0;
                $.each(self.users(), function (i, u) {
                    //改用.score()
                    total += u.score();
                });
                return total;
            });
        }
 
        $(function () {
            var vm = new MyViewModel();
            //預先增加一些User
            vm.users.push(
                new UserViewModel("M1", "Jeffrey", 32767));
            vm.users.push(
                new UserViewModel("M2", "Darkthread", 65535));
            //按鈕時動態增加User
            var c = 2;
            $("#btnAddUser").click(function () {
                var now = new Date(); //用時間產生隨機屬性值
                vm.users.push(new UserViewModel(
                    "M" + c++,
                    "P" + "-" + now.getSeconds() * now.getMilliseconds(),
                    now.getMilliseconds()));
            });
 
            $("#btnChgScore").click(function () {
                //改用score()設定內容
                vm.users()[0].score(9999);
            });
 
            ko.applyBindings(vm);
        });
    </script>
    <style>
        table { width: 400px }
        td,th { border: 1px solid gray; text-align: center }
        
    </style>
</head>
<body>
<input type="button" value="新增User" id="btnAddUser" />
<span data-bind="text: users().length"></span> 筆,
合計 <span data-bind="text: totalScore"></span>
<table>
    <thead>
        <tr><th>Id</th><th>姓名</th><th>積分</th><th></th></tr>
    </thead>
    <tbody data-bind="foreach: users">
        <tr>
            <td><span data-bind="text: id"></span></td>
            <td><span data-bind="text: name"></span></td>
            <td><span data-bind="text: score" style='text-align: right'></span></td>
            <td><a href='#' data-bind="click: $root.removeUser">移除</a></td>
        </tr>
    </tbody>
</table>
<input type="button" value="測試Score變更" id="btnChgScore" />
</body>
</html>
[KO系列]
http://www.darkthread.net/kolab/labs/default.aspx?m=post

Comments

Be the first to post a comment

Post a comment