Knockout ObservableArray not updating HTML Foreach

拈花ヽ惹草 提交于 2019-12-08 15:56:14

问题


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.

So the HTML is

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

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>

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!


回答1:


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

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.

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

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

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



来源:https://stackoverflow.com/questions/21804009/knockout-observablearray-not-updating-html-foreach

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!