使用knockout.js无法正确更新数据

时间:2013-11-12 20:10:45

标签: javascript jquery ajax codeigniter knockout.js

一周前我刚开始使用knockout.js,所以希望这很简单。我花了大约5个小时搜索谷歌和这个网站,我见过的所有建议似乎都没有用。我已经尝试将pagedPlayerList更改为justList,以删除代码中的那部分作为问题。

我有这个代码用knockout.js显示一些数据

<table class="table table-striped table-bordered">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>Name</th>
                        <th>Attack</th>
                        <th>Defense</th>
                        <th>Level</th>
                        <th>IPH</th>
                        <th>Syndicate</th>
                        <th>Last Modified</th>
                        <th style="width: 100px; text-align:right;" />
                    </tr>
                </thead>
               <tbody data-bind=" template:{name:playerTemplateToUse, foreach: pagedPlayerList }"></tbody>
            </table>

            <ul class="pagination">
                <li data-bind="css: { disabled: pageIndex() === 0 }"><a href="#" data-bind="click: previousPage">&laquo;</a></li>
            </ul>
            <ul class="pagination" data-bind="foreach: allPlayerPages">
                <li data-bind="css: { active: $data.pageNumber === ($root.pageIndex() + 1) }"><a href="#" data-bind="text: $data.pageNumber, click: function() { $root.moveToPage($data.pageNumber-1); }"></a></li>
            </ul>
            <ul class="pagination">
              <li data-bind="css: { disabled: pageIndex() === maxPlayerPageIndex() }"><a href="#" data-bind="click: nextPlayerPage">&raquo;</a></li>
            </ul>

            <script id="itemsPlayerTmpl" type="text/html">
               <tr>
                    <td data-bind="text: id"></td>
                    <td data-bind="text: name"></td>
                    <td data-bind="text: att"></td>
                    <td data-bind="text: def"></td>
                    <td data-bind="text: lvl"></td>
                    <td data-bind="text: iph"></td>
                    <td data-bind="text: synd_name"></td>
                    <td data-bind="text: $root.lastModDate(last_modified)"></td>
                    <td class="buttons">
                        <a class="btn btn-sm btn-primary" data-bind="click: $root.edit" href="#" title="edit"><i class="glyphicon glyphicon-edit"></i></a>
                        <a class="btn btn-sm btn-primary" data-bind="click: $root.removePlayer" href="#" title="remove"><i class="glyphicon glyphicon-remove"></i></a>
                    </td>
                </tr>
            </script>

            <script id="editPlayerTmpl" type="text/html">
                <tr>
                    <td data-bind="text: id"></td>
                    <td><input data-bind="value: name"/></td>
                    <td><input size="8" data-bind="value: att"/></td>
                    <td><input size="8" data-bind="value: def"/></td>
                    <td><input size="3" data-bind="value: lvl"/></td>
                    <td><input size="8" data-bind="value: iph"/></td>
                    <td>
                       <select data-bind="options: $root.syndList, optionsText: 'name', optionsValue: 'id', value: synd_id, selectedOptions: 'synd_id', optionsCaption: 'Please select...'"></select>
                    </td>

                    <td data-bind="text: $root.lastModDate(last_modified)"></td>
                    <td class="buttons">
                        <a class="btn btn-sm btn-success" data-bind="click: $root.savePlayer" href="#" title="save"><i class="glyphicon glyphicon-ok"></i></a>
                        <a class="btn btn-sm btn-primary" data-bind="click: $root.cancel" href="#" title="cancel"><i class="glyphicon glyphicon-trash"></i></a>
                    </td>
                </tr>
            </script>

加载页面时效果很好。问题是,我希望每2分钟自动更新一次数据,当我在显示器中加载数据时不会更新。

以下是javascript的相关部分

        self.playerList = ko.observableArray();
        <?php if(isset($playerlist)) { ?>
            self.playerList(jQuery.parseJSON('<?php echo addslashes($playerlist); ?>'));
        <?php } ?>

        self.lastModDate = function(data){
            var myDate = new Date(data * 1000);
            var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
            var month = months[myDate.getMonth()];
            var date = myDate.getDate();
            var year = myDate.getFullYear();
            var time = date+', '+month+' '+year;
            return time;
        }
        // ALL PLAYERS TAB       
        self.addPlayer = function () {
            var newItem = new Player();
            self.playerList.push(newItem);
            self.selectedItem(newItem);
            self.moveToPage(self.maxPlayerPageIndex());
        };
        self.removePlayer = function (item) {
            if (item.id) {
                if (confirm('Are you sure you wish to delete this item?')) {
                    $.post('<?php echo base_url('front/deleteplayer'); ?>', item).complete(function (result) {
                        if(result = '1'){
                            toastr.success("The player has been removed.", "");
                            self.playerList.remove(item);
                            if (self.pageIndex() > self.maxPlayerPageIndex()) {
                                self.moveToPage(self.maxPlayerPageIndex());
                            }
                        } else {
                            toastr.error("There was a problem removing the player", "");
                        }
                    });
                }
            }
            else {
                self.list.remove(item);
                if (self.pageIndex() > self.maxPlayerPageIndex()) {
                    self.moveToPage(self.maxPlayerPageIndex());
                }
            }
        };
        self.savePlayer = function () {
            var item = self.selectedItem();
            $.post('<?php echo base_url('front/saveplayer'); ?>', item, function (result) {
                console.log(item);
                toastr.success("Your changes have been saved.", "");
                self.selectedItem(null);
            });

        };
        self.pagedPlayerList = ko.dependentObservable(function () {
            var size = self.pageSize();
            var start = self.pageIndex() * size;
            return self.playerList().slice(start, start + size);
        });
        self.maxPlayerPageIndex = ko.dependentObservable(function (list) {
            return Math.ceil(self.playerList().length / self.pageSize()) - 1;
        });
        self.nextPlayerPage = function () {
            if (self.pageIndex() < self.maxPlayerPageIndex()) {
                self.pageIndex(self.pageIndex() + 1);
            }
        };
        self.allPlayerPages = ko.dependentObservable(function () {
            var pages = [];
            for (i = 0; i <= self.maxPlayerPageIndex() ; i++) {
                pages.push({ pageNumber: (i + 1) });
            }
            return pages;
        });
        self.playerTemplateToUse = function (item) {
            return self.selectedItem() === item ? 'editPlayerTmpl' : 'itemsPlayerTmpl';
        };
        // END ALL PLAYERS TAB

        self.edit = function (item) {
            self.selectedItem(item);
            self.currentSynd(item.synd_id);
        };

        self.cancel = function () {
            self.selectedItem(null);
        };
        self.previousPage = function () {
            if (self.pageIndex() > 0) {
                self.pageIndex(self.pageIndex() - 1);
            }
        };
        self.moveToPage = function (index) {
            self.pageIndex(index);
        };

然后这是绑定/更新代码

    // SELF UPDATING DATA
    update = function() {
        siteModel.updatePlayerList();
        console.log(siteModel.playerList);
    }

    var siteModel = new siteModel();
    window.setInterval(update,60000);
    ko.applyBindings(siteModel);

这是updatePlayerList函数

        self.updatePlayerList = function(){
            $.ajax({
                url:'<?php echo base_url('front/listplayers'); ?>',
                success:function(data) {
                    var obj = jQuery.parseJSON(data);
                    self.playerList = (obj);
                }
            });
        }

updatePlayerList第一次触发这是服务器返回内容的摘录:

[{"id":"19","name":"AlDavisJR","att":"818741","def":"895287","lvl":"227","iph":"2804866","synd_id":"9","last_modified":"1384284327","synd_name":"FIGHT CLUB"},{"id":"15","name":"aLEX","att":"95748","def":"112386","lvl":"227","iph":"16033","synd_id":"15","last_modified":"1384240593","synd_name":"iron"}]

但是console.log(self.playerList);显示空白值。运行console.log的第二次以及随后的任何时间都会显示正确的数据。

问题是表始终显示首次加载页面时加载的数据。如果我修改数据库,则ajax调用会返回新数据,但不会上传该站点。

1 个答案:

答案 0 :(得分:0)

有很多代码,所以可能会有更多的代码,但我发现的第一件事是你在self.updatePlayerList函数中更新了错误的数据。

var obj = jQuery.parseJSON(data);
self.playerList = (obj); // This assigns obj to self.playerList, overwriting the observableArray

取而代之的是

self.playerList(obj); // This keeps the observable intact, and assigns obj as it's new internal value

如果能解决这个问题,请告诉我!

修改

另外,你的console.log第一次出现空白的原因是因为updatePlayerList是一个异步函数(因为你的ajax调用是异步执行的)。因此,将调用ajax函数,并且在检索数据时,您已将observableArray的值输出到控制台。相反,您将要等到成功回调触发,然后在那里登录到控制台以检查值是否正确。

另一个可能有用的提示:当您将observable记录到控制台时,您将无法查看observable的实际值。辅助函数ko.toJS(yourObservableHere)ko.toJSON(yourObservableHere)对于检索(嵌套)可观察对象的实际值非常有用。第一个用你输入的任何东西制作一个简单的javascript对象(删除可观察的包装器),第二个做同样的事情,但是将它全部输出到一个JSON字符串。这对于在UI中进行调试非常有用(例如<div data-bind="text: ko.toJSON(yourViewModel)"></div>