【问题标题】:Bind viewmodel to ui after ajax call succeeds Knockoutajax调用成功后将viewmodel绑定到ui
【发布时间】:2012-12-15 01:39:42
【问题描述】:

我在每行数据中都有一个全选切换复选框和复选框。

现在从服务器返回的数据没有isSelected Observable。我为每一行添加了 'isSelected' observable。但是isSelected observable 并没有绑定到每一行的复选框。

这是视图模型:

var folderViewModel = function () {
    var self = this;
    self.Folders = ['Inbox', 'Archive', 'Sent', 'Spam'];
    self.SelectedFolder = ko.observable();
    self.Mails = ko.observableArray([]);
    self.SelectedMail = ko.observable();
    self.SelectAll = ko.observable(false);

    self.navigate = function (folder) {
        self.SelectedFolder(folder);
        //$.get('/Api/MailBox', { folder: folder }, self.Mails);

        $.ajax({
            url: "/Api/Mailbox",
            data: { folder: folder },
            success: function (data) {
                ko.mapping.fromJS(data, {}, self.Mails);
                ko.utils.arrayForEach(self.Mails(), function (mail) {
                    mail.isSelected = ko.observable(true);
                    mail.isSelected.subscribe(function (myvalue) {
                        console.log(myvalue);
                    });
                });
                console.log(ko.toJSON(self.Mails()));
            },
            statusCode: {
                404: function () {
                    alert("No Mail");
                }
            }
        });

        //ko.mapping.fromJS(data, {}, self.Mails);
        //console.log(ko.toJSON(self.Mails));
    };

    self.SelectAll.subscribe(function (newValue) {
        ko.utils.arrayForEach(self.Mails(), function (mail) {
            console.log(mail.isSelected());
            mail.isSelected(newValue);

        });
        console.log(newValue);
    }, self);

    this.navigate("Inbox");
};
ko.applyBindings(new folderViewModel());

这里是绑定。

<table class="table table-bordered table-striped table-condensed table-hover">
<thead>
    <tr>
        <th>
            <input type="checkbox" data-bind="checked: SelectAll"/>
            @*<input type="checkbox" />*@
        </th>
        <th>
            From
        </th>
        <th>
            To
        </th>
        <th>
            Subject
        </th>
        <th>
            Date
        </th>
    </tr>
</thead>
<tbody data-bind="foreach:Mails">
    <tr data-bind="click:$root.navigateToMail">
        <td style="width: 15px">
            <input type="checkbox" data-bind="checked: $root.isSelected">
            @*<input type="checkbox">*@
        </td>
        <td data-bind="text: From">
        </td>
        <td data-bind="text: To">
        </td>
        <td data-bind="text: Subject">
        </td>
        <td data-bind="text: MailDate">
        </td>
    </tr>
</tbody>

&lt;input type="checkbox" data-bind="checked: $root.isSelected"&gt; 复选框未绑定到mails.isSelected=ko.obsevable(true) 中的 ajax 数据。可能是什么问题?

【问题讨论】:

    标签: knockout.js knockout-mapping-plugin knockout-2.0


    【解决方案1】:

    首先,感谢使用 learn.knockoutjs.com 示例,令人惊叹的资源。

    您的错误是 KnockoutJS 中的一个常见缺陷:您正在修改模型而不更新绑定到它的 observable。请参阅以下几行 -

    ko.mapping.fromJS(data, {}, self.Mails);
    ko.utils.arrayForEach(self.Mails(), function (mail) { ... });
    

    如果您看到,您首先为邮件创建模型,然后添加一个额外的 observable。这个 observable 应该附加到哪个上下文?如果不更新每封邮件的值,您的mail.isSelected 将永远不会添加到邮件对象中。

    有两种方法可以解决这个问题。第一个,你更新 forEach 数组中的邮件模型:

    ko.utils.arrayForEach(self.Mails(), function (mail, index) { 
        // Add up the isSelected observable
        self.Mails()[index] = mail; 
    });
    

    这对可观察数组有一个性能问题,您可以阅读here。基本上,您希望创建一个临时数组并更新整个可观察数组,而不是每次调用Mails()

    另一种方法很简单:交换你创建邮件模型的顺序:

    ko.utils.arrayForEach(self.Mails(), function (mail) { ... });
    ko.mapping.fromJS(data, {}, self.Mails);
    

    首先,您将附加到您的 observable 的数据对象,然后您告诉您的 viewmodel “嘿!我们有一个新模型来保存它,它具有来自 data 的这些属性加上我刚刚添加的 observable isSelected,请注意绑起来?”

    话虽如此,HTML 中的属性是 checked: isSelected 而不是 checked: $root.isSelected,这就是它在 SelectAll 上工作的原因(有点),因为 isSelected 被绑定到您的 ViewModel您的邮件模型。你可以用这个方便的语句来调试它:

    // In any row inside your data
    <td data-bind="text: ko.toJSON($data)">DEBUG DATA</td>
    

    应该就是这样,您可以在这里看到您的代码及其所有解决方案:http://jsfiddle.net/jjperezaguinaga/VTuHA/。我添加了一些示例数据(使用 JsFiddle 的 /echo/json/ 功能)并删除了一些东西,以及我用来调试的最后一个代码的额外列。在最后一列中,您可以看到每次单击复选框时都会更新值 isSelected

    【讨论】:

    • 优秀的答案,但注意解释一部分。我了解您实际上将 observable 属性附加到数据,然后使用敲除映射映射它的事实。抱歉我是菜鸟,但他们两个不是同一件事吗?如果您首先创建一个可观察数组,然后附加可观察属性(这显然是我所做的,但没有工作)。所以请解释一下我的错在这里?
    • 没问题,也没有菜鸟问题 :) 一件事是 ViewModel(想想你的整个函数对象,使用 $root 标签访问的对象,另一个是你的邮件模型,即只是一个表达式来描述具有一堆属性的特定类。您的 ViewModel 有一个邮件模型的集合(ko.observableArray);您的问题是您将 isSelected 绑定到您的 ViewModel($root.isSelected 工作),而您需要将其绑定到每个邮件模型和适当的范围。
    • 这与Javascript中著名的this字有关。当您将 ko.observable 附加到 foreach 中的 Mail 对象时,它的上下文是什么?它是 ViewModel,因此您将其绑定到整个 ViewModel 而不是您想要的 Model。顺便说一句,Model 只是从 Backbone 复制的表示“类”的语法,它并没有真正用于 KnockoutJS;希望这个词的使用可以帮助您看到您的邮件是来自特定类的特定对象,而不是让您感到困惑:)
    • 哦,好的,谢谢。我想我明白了。我实际上将它绑定到基本函数,但没有绑定到每个邮件对象。我想在确定之前我需要做一个研究。不过非常感谢。我会保留你的陈述作为参考,同时考虑到将来:)
    • 说得对,没问题,请随时继续询问 SO,我们会尽力提供帮助。
    【解决方案2】:

    isSelected 不是添加到每个 mail 项目上,而不是在 root 视图模型中吗?如果是这样,您的绑定应该是:

    <input type="checkbox" data-bind="checked: isSelected">
    

    注意:我也没有在root 视图模型中看到navigateToMail 方法,这也会导致问题。

    【讨论】:

    • 我确实做到了。但它说 isSelected 没有定义
    猜你喜欢
    • 2017-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多