Knockout ObservableArray不更新HTML Foreach

use*_*493 9 javascript ko.observablearray knockout.js

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

所以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>
Run Code Online (Sandbox Code Playgroud)

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

<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>
Run Code Online (Sandbox Code Playgroud)

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

Rob*_*und 3

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

首先,您再次调用构造函数,但引用this可能没有指向您认为的对象。TweetsViewModel当您再次调用构造函数(在setTimeout调用中)时this,引用将指向该window对象。

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

self.tweets = ko.observableArray();
Run Code Online (Sandbox Code Playgroud)

所有订阅(例如 UI DOM 元素)仍将订阅旧的 observableArray,因为它们不知道变量已更改。

因此,您可能应该做的是创建一个执行数据重新加载的函数,如下所示:

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);
Run Code Online (Sandbox Code Playgroud)

另外,请注意,这总是会向 observableArray 添加推文(永远不会清除它),并且还会导致每添加一条推文就会触发一次对 observableArray 的订阅。如果您想替换该数组,您可能应该创建一个替换数组,将推文推入该数组,最后通过执行以下操作替换 observableArray 中的数组self.tweets(replacementArray);