2

我有一个名为客户的模型:

function customer(id, name, age, comments) {
    var self = this;

    self.Id = id;
    self.Name = name;
    self.Age = age,
        self.Comments = comments;

    self.addCustomer = function () {
        $.ajax({
            url: "/api/customer/",
            type: 'post',
            data: ko.toJSON(this),
            contentType: 'application/json',
            success: function (result) {
                //SOMETHINGS WRONG HERE
                customerVM();
            }
        });
    }
}

添加客户后,客户列表不会自动更新。在模型中调用 customerVM() 会进入 viewModel 函数,但永远不会进入 getCustomers 函数,所以我一定是错误地调用了 viewModel。这就是我从调试中看到的。

显示列表的函数在 viewModel 中:

function customerVM() {
    var self = this;
    self.customers = ko.observableArray([]);
    self.getCustomers = function () {
        self.customers.removeAll();
        $.getJSON("/api/customer/", function (data) {
            $.each(data, function (key, val) {
                self.customers.push(new customer(val.Id, val.Name, val.Age, val.Comments));
            });
        });
    };
}

添加客户后,我需要以某种方式调用 getCustomers 。我该怎么做?

这是客户的html

<table >
    <thead>
        <tr>
            <th>Id</th>
            <th>Name</th>
            <th>Age</th>
            <th>Comments</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: customers" >
        <tr>
            <td data-bind="text: Id"></td>
            <td data-bind="text: Name"></td>
            <td data-bind="text: Age"></td>
            <td data-bind="text: Comments"></td>
        </tr>
    </tbody>
</table>
<br />
<input type="button" id="btnGetCustomers" value="Get Customers" data-bind="click: getCustomers" />
4

3 回答 3

2

我认为你的设计实际上有一些缺陷。首先,你不想customerVM()在你打电话后的任何时候打电话ko.applyBindings(vm);(我实际上在你的 html 中没有看到任何地方)

在您的 html 页面中的某处,您应该有:

<script type="text/javascript">
    var vm = new customerVM();
    ko.applyBindings(vm);
</script>

其次,将其customerVM()视为包含一个集合customers并负责管理您的customers集合的填充,以及将集合(或单个customer)传递给您的 API 以实现持久性。意思是,我会将 addCustomer 函数从客户对象中取出,并将其移动到 customerVM 中。

    // customer is just a simple data object
    function customer(id, name, age, comments) {

            var self = this;
            self.Id = ko.observable(id);
            self.Name = ko.observable(name);
            self.Age = ko.observable(age);
            self.Comments = ko.observable(comments);
    }

    function customerVM() {

        var self = this;
        self.customers = ko.observableArray([]);

        self.getCustomers = function () {
            self.customers.removeAll();
            $.getJSON("/api/customer/", function (data) {
                $.each(data, function (key, val) {
                    self.customers.push(new customer(val.Id, val.Name, val.Age, val.Comments));
                });
            });
        };

       self.addCustomer = function (customer) {
           // pass in a single customer for persistence
       }
}
于 2013-06-05T17:39:10.677 回答
2

我认为您在这里提出的更深层次的问题是关于如何在浏览器中管理您的数据并使其与服务器上的数据保持同步。我昨天回答了一个类似的问题,您可以在这里阅读:向淘汰赛可观察数组添加新元素 - 最佳实践?

在您的问题和代码中,您似乎正在尝试将新客户插入服务器,然后在插入后将整个客户列表读回您的视图模型。你可能需要这个你没有提到的,但通常这种模式不是必需的。

插入到服务器后需要从服务器读取的最常见情况是为您刚刚添加的对象检索服务器生成的标识符。对于大多数 MV* 浏览器端框架 - 包括 Knockout - 一个常见模式是“插入” api 调用返回新元素的 ID(或您需要返回的任何数据)并简单地更新客户端版本具有新 ID 的模型。如果 ID 属性是可观察的,Knockout 将自动更新您的 UI。这是一个例子:

var customer = function(name, age, comments){
    var self = this;
    self.id = ko.observable();//unknown when created in the browser
    self.name = ko.observable(name);
    self.age = ko.observable(age);
    self.comments = ko.observable(comments);
}

var customersViewModel = function(){
    var self = this;
    self.customers = ko.observableArray([]);
    self.addCustomer = function(customer){
        self.customers.push(customer);
        $.ajax({
            url: "/api/customer/add",
            type: 'post',
            data: ko.toJSON(this),
            contentType: 'application/json',
            success: function (result) {
                //assuming result will contain the server-side customer id
                //we provide that value to our customer's id observable
                //and knockout will update the UI
                customer.id(result.newCustomerId);
                //no need to update the entire array, and 
                //our 'customer' has already been pushed into our 
                //observable array so we're done. 
            }
        });
    }
}

当您的客户处于“待定”状态时(浏览器正在等待服务器响应插入 api 调用),您知道客户不会有 ID。您可以在绑定中使用它来将“待定”类应用于您的客户,如下所示:

<tbody data-bind="foreach: customers" >
    <tr data-bind="css : {'pending': !id()}">
        <td data-bind="text: id"></td>
        <td data-bind="text: name"></td>
        <td data-bind="text: age"></td>
        <td data-bind="text: comments"></td>
    </tr>
</tbody>

我希望这有帮助!

于 2013-06-05T21:55:11.890 回答
1

如果您像 Tom 建议的那样执行了 applyBindings:

<script type="text/javascript">
    var vm = new customerVM();
    vm.getCustomers();
    ko.applyBindings(vm);
</script>

然后您的 addCustomer 方法应如下所示:

self.addCustomer = function () {
    $.ajax({
        url: "/api/customer/",
        type: 'post',
        data: ko.toJSON(this),
        contentType: 'application/json',
        success: function (result) {
           vm.getCustomers(); //*******THIS IS THE CHANGE YOU NEED
        }
    });
}

虽然,我同意 Tom 的观点,将 addCustomer 方法移到根模型中会更合适。

于 2013-06-05T21:06:00.613 回答