如何在ViewModel Knockout中调用函数

时间:2013-06-05 17:22:11

标签: knockout.js

我有一个名为customer的模型:

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" />

3 个答案:

答案 0 :(得分:2)

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

你的html页面中应该有:

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

其次,将customerVM()视为包含customers的集合,并负责管理您的customers集合的填充,以及传递集合(或单个{{} 1}})你的API的持久性。这意味着,我将把addCustomer函数从客户对象中移出并移动到customerVM中。

customer

答案 1 :(得分: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方法移动到根模型中会更合适。

答案 2 :(得分:1)

我认为您在这里提出的更深层次的问题是如何在浏览器中管理数据并使其与服务器上的数据保持同步。我昨天回答了一个类似的问题,你可以在这里阅读:Adding new elements to a knockout observable array - best practices?

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

插入到服务器之后,从服务器要求读取的最常见情况是检索服务器生成的刚刚添加的对象的标识符。对于大多数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>

我希望这有帮助!