Knockout ObservableArray不更新HTML Foreach [英] Knockout ObservableArray not updating HTML Foreach

查看:108
本文介绍了Knockout ObservableArray不更新HTML Foreach的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有一个可观察的阵列工作正常,但UI不会更新。我看过很多人遇到这个问题,但是我没有看到它。

So I've got an observablearray that works fine, but the UI doesn't update. I've read lots of people running into this TYPE of issue, but I'm not seeing it.

所以HTML是

            <tbody data-bind="foreach: tweets">
            <tr>
                <td>
                    <span data-bind="visible: created_at" class="label label-success">Yup</span>
                </td>
                <td><p><b data-bind="text: screen_name"></b></p></td>
                <td><p><b data-bind="text: id"></b></p></td>
                <td><p data-bind="text: text"></p></td>
                <td><p data-bind="text: created_at"></p></td>
            </tr>
            </tbody>

Javascript是一个调用API并从中构建数组的函数。

And the Javascript is a function that calls an API and builds an array from it.

<script type="text/javascript">
        function TweetsViewModel() {
            var self = this;
            self.tasksURI = 'http://localhost:8000/api/v1/tweet/';
            self.tweets = ko.observableArray();

            self.ajax = function(uri, method, data) {
                var request = {
                    url: uri,
                    type: method,
                    contentType: "application/json",
                    Accept: "application/json",
                    cache: false,
                    dataType: 'json',
                    data: JSON.stringify(data)
                };
                return $.ajax(request);
            }

            self.ajax(self.tasksURI, 'GET').done(function(data) {
                for (var i = 0; i < data.objects.length; i++) {
                    var tweet = this;
                    tweet.created_at = ko.observable(data.objects[i].created_at)
                    tweet.text = ko.observable(data.objects[i].text)
                    tweet.id = ko.observable(data.objects[i].id)
                    tweet.screen_name = ko.observable(data.objects[i].twitteruser.screen_name)
                    self.tweets.push(tweet)
                }
            });
            setTimeout(TweetsViewModel, 10000)
        }
        ko.applyBindings(new TweetsViewModel());
    </script>

仅出于测试目的,我使用setTimeout重新运行对API的调用并更新数组。数组正确更新,但UI没有。我为我的无知道歉(长期以来一直是后端开发者,这是我10年来第一次在Javascript上运行)。任何帮助非常感谢!

Just for testing purposes, I'm using the setTimeout to just rerun the call to the API and update the array. The Array gets updated properly, but the UI doesn't. I apologize for my ignorance (been a backend dev for a longtime, this is my first run at Javascript in 10 years). Any help much appreciated!

推荐答案

问题是你永远不会更新observableArray。

The problem is that you're never updating the observableArray.

首先,你再次调用构造函数,但是这个引用可能没有指向你认为对象。再次调用 TweetsViewModel 构造函数时(在 setTimeout 调用中) this 引用将指向窗口对象。

To start with, you're calling the constructor again, but the this reference is probably not pointing to the object you think. When you call the TweetsViewModel constructor again (in the setTimeout call) the this reference will point to the window object.

即使你得到这个引用指向正确的对象(可以使用函数具有的 apply 方法,但这不是重点)你仍然会不要更新observableArray,因为你要将 self.tweets 变量设置为行上的新observableArray

Even if you get the this reference to point to the right object (which is possible using the apply method that functions have, but that's beside the point) you would still not be updating the observableArray, since you'd be setting the self.tweets variable to a new observableArray on the line

self.tweets = ko.observableArray();

所有订阅,例如UI DOM元素仍然会订阅旧的observableArray,因为他们不知道变量已经改变了。

All subscriptions, e.g. the UI DOM elements, would still be subscribed to the old observableArray since they would not know that the variable has changed.

所以你应该做的就是创建一个函数执行重新加载数据,如下所示:

So what you should probably do is to create a function which performs reload of the data, like the following:

self.reloadData = function(){
    self.ajax(self.tasksURI, 'GET').done(function(data) {
        for (var i = 0; i < data.objects.length; i++) {
            // Important: Create a new tweet object instead of using 'this' here.
            var tweet = {};
            tweet.created_at = ko.observable(data.objects[i].created_at)
            tweet.text = ko.observable(data.objects[i].text)
            tweet.id = ko.observable(data.objects[i].id)
            tweet.screen_name = ko.observable(data.objects[i].twitteruser.screen_name)
            self.tweets.push(tweet)
        }
    });
}
setTimeout(self.reloadData, 10000);

另外,请注意这总是会将信息添加到observableArray(从不清除它)以及它每个推文添加后,会导致observableArray的订阅触发一次。如果你想要替换数组,你应该创建一个替换数组,将推文推送到该数组,最后通过 self.tweets(replacementArray); 。

Also, be aware that this would always add tweets to the observableArray (never clear it) and also it would cause the subscriptions to the observableArray to fire once per tweet added. If you would want to replace the array you should probably create a replacement array, push tweets into that array and finally replace the array in the observableArray by doing self.tweets(replacementArray);.

这篇关于Knockout ObservableArray不更新HTML Foreach的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆