javascript - Knockout ObservableArray not updating HTML Foreach - Stack Overflow

So I've got an observablearray that works fine, but the UI doesn't update.I've read lo

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!

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!

Share Improve this question asked Feb 15, 2014 at 21:41 user3314493user3314493 931 silver badge3 bronze badges 0
Add a ment  | 

1 Answer 1

Reset to default 3

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

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745187600a4615710.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信