【问题标题】:Foreach not correctly updating viewForeach 没有正确更新视图
【发布时间】:2016-03-19 00:59:55
【问题描述】:

我正在努力让一个简单的单页应用程序工作。检查浏览器中的各种调试工具后,我可以看到它正确地触发了搜索并以正确的格式返回 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());

【问题讨论】:

    标签: javascript json knockout.js


    【解决方案1】:

    您将 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); })
      });
    });
    

    这是一个完整的演示:

    // 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());
    li:hover { cursor: pointer; color: red; }
    <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>

    【讨论】:

    • 感谢您的建议。我已经实现了您所做的更改以及虚假数据,并且页面功能正常。我仍然不确定如何删除虚假数据并让它引用我的真实 JSON。
    • 解决了最后一步。没有正确猜测回调是 JSON,因此必须在 .get 函数中明确说明。
    猜你喜欢
    • 2023-03-17
    • 2012-12-17
    • 1970-01-01
    • 1970-01-01
    • 2020-04-06
    • 2021-12-29
    • 1970-01-01
    • 2015-03-15
    • 2017-03-09
    相关资源
    最近更新 更多