KnockoutJS - ko.computed和AJAX请求令人沮丧

时间:2012-12-09 01:07:10

标签: knockout.js knockout-2.0

我只是想从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)

根据更多说明,我已经缩小了一些问题。将callback定义为viewModel上的函数似乎不起作用(我不确定为什么)但声明内联函数确实会产生......不同的东西。但仍然没有工作。这是一个更新。

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

然后我开始看到结果。我想我快到了那里......

3 个答案:

答案 0 :(得分:13)

正如SLaks指出的那样,由于调用是异步调用的,所以你不能这样做,即“read”函数在检索到响应之前返回。我会推荐这样的东西:

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);
}

答案 1 :(得分:5)

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

self.htmlUserName = ko.observable();

self.computedUserName = ko.computed(function () {
    $.ajax(
    ....
    success: function (result) {
    self.htmlUserName(result);
    }
}

答案 2 :(得分:2)

Knockout绑定不支持异步计算。

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

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