14

我只是想从 ajax 请求中提取一些数据。ajax 调用有效 - 我知道数据已被检索。但它只是没有设置 ko.computed 的值......

        function viewModel() {
            this.Id = ko.observable("@Model.Identity()");
            this.Points = ko.computed({ 
                read: function () {
                    $.ajax({
                        url: '/skills/points',
                        data: { id: this.Id },
                        type: 'get',
                        success: function (data) {
                            return data;
                        }
                    });
                },
                owner: this
            });
        }

所以像...这样的电话

<span data-bind="text: Points"></span>

只是不工作。谁能帮我弄清楚我做错了什么?

更新

我正在使用以下代码,遵循 RPN 的建议 - 我根本无法让它发挥作用。它不会查看控制器,也不会返回数据……它什么也不做。我已经尝试了所有三个示例,但均未成功。

<script type="text/javascript">
    //an observable that retrieves its value when first bound
    ko.onDemandObservable = function (callback, target) {
        var _value = ko.observable();  //private observable

        var result = ko.computed({
            read: function () {
                //if it has not been loaded, execute the supplied function
                if (!result.loaded()) {
                    callback.call(target);
                }
                //always return the current value
                return _value();
            },
            write: function (newValue) {
                //indicate that the value is now loaded and set it
                result.loaded(true);
                _value(newValue);
            },
            deferEvaluation: true  //do not evaluate immediately when created
        });

        //expose the current state, which can be bound against
        result.loaded = ko.observable();
        //load it again
        result.refresh = function () {
            result.loaded(false);
        };

        return result;
    };

    $(document).ready(function () {
        function User(id, name) {
            this.Id = ko.observable(id);
            this.Name = ko.observable(name);
        }
        function viewModel() {
            var self = this;

            this.User = ko.onDemandObservable(this.Update, this);

            this.Update = function () {
                return $.ajax({
                    url: '/home/user/',
                    data: { id: 1 },
                    dataType: 'json'
                }).pipe(function (data) {
                    return new User(data.Id, data.Name);
                });
            };
        };
        var model = new viewModel();
        ko.applyBindings(model);
        model.User();
    });
</script>

<span data-bind="text: User.Name"></span>

更新 (2)

按照更多说明,我缩小了一些问题的范围。将 viewModel定义callback为函数似乎不起作用(我不确定为什么),但声明内联函数确实会产生......不同的东西。仍然无法正常工作。这是一个更新。

<script type="text/javascript">
    //an observable that retrieves its value when first bound
    ko.onDemandObservable = function (callback, target) {
        var _value = ko.observable();  //private observable

        var result = ko.computed({
            read: function () {
                //if it has not been loaded, execute the supplied function
                if (!result.loaded()) {
                    callback.call(target);
                }
                //always return the current value
                return _value();
            },
            write: function (newValue) {
                //indicate that the value is now loaded and set it
                result.loaded(true);
                _value(newValue);
            },
            deferEvaluation: true  //do not evaluate immediately when created
        });

        //expose the current state, which can be bound against
        result.loaded = ko.observable();
        //load it again
        result.refresh = function () {
            result.loaded(false);
        };

        return result;
    };

    $(document).ready(function () {
        function User(id, name) {
            this.Id = ko.observable(id);
            this.Name = ko.observable(name);
        }
        function viewModel() {
            var self = this;

            this.User = ko.onDemandObservable(function(){
                $.ajax({
                    url: '/home/user/',
                    data: { id: 1 },
                    dataType: 'json',
                    success: function (data) {
                        self.User(new User(data.Id, data.Name));
                    }
                });
            }, this);

            //this.Update = function () {
            //  $.ajax({
            //      url: '/home/user/',
            //      data: { id: 1 },
            //      dataType: 'json',
            //      success: function (data) {
            //          self.User(new User(data.Id, data.Name));
            //      }
            //  });
            //};
        };
        var model = new viewModel();
        ko.applyBindings(model);
        model.User();
    });
</script>

然后尝试显示检索到的任何数据仍然失败。

<span data-bind="text: User.Name"></span>

更新 (3)

有点突破!如果我将声明性绑定更改为如下所示..

<span data-bind="with: User">
    <span data-bind="text: Id"></span>
    <span data-bind="text: Name"></span>
</span>

然后我开始看到结果。我想我快到了……

4

3 回答 3

15

正如 SLaks 指出的那样,由于调用是异步进行的,因此您不能这样做,即“读取”函数在检索到响应之前返回。我会推荐这样的东西:

function viewModel() {
    var self = this;
    this.Id = ko.observable("@Model.Identity()");
    this.Points = ko.observable(0);

    var refreshPoints = function() {
        $.ajax({
            url: '/skills/points',
            data: { id: self.Id() }, // <-- you need () here!
            type: 'get',
            success: function (data) {
                self.Points(data);
            }
        });
    };

    // Now subscribe to the ID observable to update the points whenever the 
    // ID gets changed:
    this.Id.subscribe(refreshPoints);
}
于 2012-12-09T01:26:15.570 回答
6

只需将一个可观察变量绑定到 html 变量并在 ko.computed 字段中更新该字段。不要直接将 ko.computed 字段绑定到 html 变量。

self.htmlUserName = ko.observable();

self.computedUserName = ko.computed(function () {
    $.ajax(
    ....
    success: function (result) {
    self.htmlUserName(result);
    }
}
于 2013-03-13T16:18:00.530 回答
2

Knockout 绑定不支持异步计算。

相反,您应该使用常规属性并将其设置为 AJAX 请求的结果。
您可以通过在依赖属性的更改处理程序中重新发送 AJAX 请求来使其可观察。

您还可以使用单独的占位符值将加载指示器添加到绑定的 UI。

于 2012-12-09T01:25:25.293 回答