值未绑定到 knockout.js 中的 Ko.observable

Value not bound to Ko.observable in knockout.js

这是我用来绑定文本框的代码:

var CategoryViewModel = {
    categoryModel: ko.observable({
        categoryId: ko.observable(),
        categoryName: ko.observable(),
        active: ko.observable()
    }),
    GetCategoryById: function (data, event) {
        CategoryViewModel.ClickId(event.target.id);
        var ajaxUrl = ApplicationRootUrl("GetCategoryById", "Category") + "/" + CategoryViewModel.ClickId();

        $.ajax({
            type: "GET",
            contentType: "application/json; charset=utf-8",
            url: ajaxUrl,
            dataType: "json",
            success: function (data) {
                if (data.isSuccess) {
                    // This value got bind to textbox
                    CategoryViewModel.categoryModel(data.data);
                } 
            },
            error: function (err) {

            }
        });
    },
    CategoryAddButton: function() {
        CategoryViewModel.categoryModel();
        $('#addCategoryModel').modal('toggle');
    }            
};

$(document).ready(function () {
    ko.applyBindings(CategoryViewModel, document.getElementById("categoryMain"));
});

单击按钮时调用 CategoryAddButton 方法。我正在尝试清空此方法中的模型值。

这里是 HTML:

<input type="text" name="CategoryName" class="form-control" placeholder="Enter Category Name" data-bind="textinput: categoryModel().categoryName">

文本框值在 ajax 调用时绑定。但是,调用 CategoryAddButton 方法后,该值未绑定到文本框。

首先,我建议您使用不同的方法根据您编写的内容创建视图模型。尽管一些初学者的例子也是这样做的,但这只是为了简单起见——实际上,将视图模型创建为对象文字通常不是一个好主意。这是因为正如 here, here, and here 在许多其他重复项中发布的那样,访问同一对象的另一个 属性 可能会变得很脏,尽管该任务应该是多么微不足道。

因此,要解决此问题,您应该改用构造函数和 new 运算符,因为这使您可以更轻松地操作对象。但是,我添加此内容只是为了指导您编写更清晰的代码,仅使用构造函数和 new 对象语法并不能解决问题。

所以让我们回到你的问题。要找出您的代码不起作用的原因,请查看您在绑定起作用时如何操作数据以及在不起作用时如何操作数据。

您说在 AJAX 调用成功后,值得到正确更新,因此绑定有效。这是因为在 AJAX 调用的 success 回调中,您实际上是将一个对象传递给 categoryModel。但是,我要指出,您传递给它的不是可观察对象,而只是一个普通对象,而您最初创建它时其属性是可观察对象!因此,即使在那里,您也可能 运行 遇到问题。

您还说点击按钮后,值没有更新。我不太确定你想在这里实现什么;你想显示什么,数据应该从哪里来?因为你写的这行代码:

CategoryViewModel.categoryModel();

只是一个 getter -- 它不会以任何方式改变对象,您只是在读取它的值。不实际修改,当然什么都不会改变。

所以,我会给你一个实现整个事情的可能方法,我建议你阅读更多关于 javascript 对象构造函数以及如何使用它们正确使用 knockout 的内容。

function categoryViewModel() {
    var self = this;

    // Don't wrap these in another observable, that's totally needless.
    this.categoryId = ko.observable(null);
    this.categoryName = ko.observable(null);
    this.active = ko.observable(true);

    // You could actually define this on the prototype
    // but I don't want to make it even more complicated
    this.GetCategoryById = function(categoryId) {
        // You could do this if the value passed can either be a plain value 
        // or an observable; ko will return the actual value to you.
        var catId = ko.utils.unwrapObservable(categoryId);

        var ajaxUrl = ApplicationRootUrl("GetCategoryById", "Category") + "/" + catId;

        $.ajax({
            type: 'GET',
            contentType: "application/json; charset=utf-8",
            url: ajaxUrl,
            dataType: "json",
            success: function(data) {
                if (data.isSuccess) {
                    // Correct the object references according to
                    // the structure of the response if needed.
                    self.categoryId(data.data.id);
                    self.categoryName(data.data.name);
                    self.active(data.data.isActive);
                }
            },
            error: function(err) {
            }
        });
    };

    this.CategoryAddButton = function() {
        self.categoryId(null);
        self.categoryName(null);
        self.isActive(true); // If you want to default to true.
        $('#addCategoryModel').modal('toggle');
    };
};

$(document).ready(function () {
    ko.applyBindings(new categoryViewModel(), document.getElementById("categoryMain"));
});

你的 HTML 可能是:

<input type="text" name="CategoryName" class="form-control" data-bind="textInput: categoryName" />

至于 GetCategoryById 函数,如果您将其分配给函数原型,而不是将 "copy" 分配给每个创建的对象,那就更好了。但由于我假设您只会拥有 1 个视图模型实例,所以我暂时认为这超出了范围。