Foreach没有正确更新视图

时间:2015-12-13 14:00:49

标签: javascript json knockout.js

我很难让一个简单的单页应用程序工作。检查浏览器中的各种调试工具后,我可以看到它正确触发搜索并以正确的格式返回JSON。但是,foreach绑定似乎没有触发,并且表永远不会填充。

相关的HMTL:

<!-- Folders -->
<ul class="folders" data-bind="foreach: folders">
    <li data-bind="text: $data, 
                   css: { selected: $data == $root.chosenFolderId() },
                   click: $root.goToFolder"></li>
</ul>

<!-- Tickets grid -->
<table class="tickets" data-bind="with: chosenFolderData">
    <thead><tr><th>ID</th><th>Description</th><th>Status</th></tr></thead>
    <tbody>
    <!-- ko foreach: tickets -->
        <tr data-bind="click: $root.goToTickets">
            <td data-bind="text: id()"></td>
            <td data-bind="text: message()"></td>
            <td data-bind="text: is_active()"></td>
        </tr>     
        <!-- /ko -->
    </tbody>
</table>

脚本:

function WebticketViewModel() {
    // Data
    var self = this;
    self.folders = ['All', 'Open', 'Closed'];
    self.chosenFolderId = ko.observable();
    self.chosenFolderData = ko.observable();
    self.chosenTicketData = ko.observable();

    // Behaviours    
    self.goToFolder = function(folder) { 
        self.chosenFolderId(folder); // Mark folder as selected
        self.chosenTicketData(null); // Stop showing a ticket
        $.get('search.php', { folder: folder }, self.chosenFolderData); // Fetch folder data and update view
    };

    self.goToTickets = function(ticket) { 
        self.chosenFolderId(ticket.folder); // Mark ticket as selected
        self.chosenFolderData(null); // Stop showing a folder
        $.get('search.php', { ticketID: ticket.id }, self.chosenTicketData); // Fetch ticket data and update view
    };

    // Show inbox by default
    self.goToFolder('All');
};

ko.applyBindings(new WebticketViewModel());

1 个答案:

答案 0 :(得分:0)

您可以使用observable函数作为ajax调用的success回调函数。不要这样做。相反,有一个适当的函数来处理结果。您已经在您的视图中期望得多,因为tickets似乎具有可观察的属性。

为故障单创建一个构造函数,如下所示:

function Ticket(data) {
  this.id = ko.observable(data.id);
  this.message = ko.observable(data.message);
  this.is_active = ko.observable(data.is_active);
}

按照这些方式处理ajax调用:

$.get('search.php', { folder: folder }, function(data) {
  self.chosenFolderData({
    tickets: data.map(function(d) { return new Ticket(d); })
  });
});

这是一个完整的演示:

&#13;
&#13;
// Fake data:
$ = {
  get: function(url, data, callback) {
    if (data.folder && data.folder === "All") { callback([{id:1, message:"My Message AAAA", is_active:true}]); }
    else if (data.folder && data.folder === "Open") { callback([{id:1, message:"My Message BBBB", is_active:false}, {id:1, message:"My Message CCCC", is_active:true}]); }
    else callback([]);
  }
};

function Ticket(data) {
  this.id = ko.observable(data.id);
  this.message = ko.observable(data.message);
  this.is_active = ko.observable(data.is_active);
}

function WebticketViewModel() {
    // Data
    var self = this;
    self.folders = ['All', 'Open', 'Closed'];
    self.chosenFolderId = ko.observable();
    self.chosenFolderData = ko.observable();
    self.chosenTicketData = ko.observable();

    // Behaviours    
    self.goToFolder = function(folder) { 
        self.chosenFolderId(folder); // Mark folder as selected
        self.chosenTicketData(null); // Stop showing a ticket
        $.get('search.php', { folder: folder }, function(data) {
              self.chosenFolderData({
                tickets: data.map(function(d) { return new Ticket(d); })
              });
        }); // Fetch folder data and update view
    };

    self.goToTickets = function(ticket) { 
        self.chosenFolderId(ticket.folder); // Mark ticket as selected
        self.chosenFolderData(null); // Stop showing a folder
        $.get('search.php', { ticketID: ticket.id }, self.chosenTicketData); // Fetch ticket data and update view
    };

    // Show inbox by default
    self.goToFolder('All');
};

ko.applyBindings(new WebticketViewModel());
&#13;
li:hover { cursor: pointer; color: red; }
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<!-- Folders -->
<ul class="folders" data-bind="foreach: folders">
    <li data-bind="text: $data, 
                   css: { selected: $data == $root.chosenFolderId() },
                   click: $root.goToFolder"></li>
</ul>

<!-- Tickets grid -->
<table class="tickets" data-bind="with: chosenFolderData">
    <thead><tr><th>ID</th><th>Description</th><th>Status</th></tr></thead>
    <tbody>
    <!-- ko foreach: tickets -->
        <tr data-bind="click: $root.goToTickets">
            <td data-bind="text: id()"></td>
            <td data-bind="text: message()"></td>
            <td data-bind="text: is_active()"></td>
        </tr>     
        <!-- /ko -->
    </tbody>
</table>
&#13;
&#13;
&#13;