2014-02-15 13 views
9

So habe ich eine Observablearray, die gut funktioniert, aber die Benutzeroberfläche wird nicht aktualisiert. Ich habe viele Leute gelesen, die in diese Art von Problem geraten, aber ich sehe es nicht.Knockout ObservableArray HTML nicht aktualisieren Foreach

So ist der HTML ist

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

Und Javascript ist eine Funktion, die eine API-Aufrufe und baut eine Reihe von ihm.

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

nur zu Testzwecken, ich bin mit der setTimeout nur den Aufruf der API erneut ausführen und das Array zu aktualisieren. Das Array wird ordnungsgemäß aktualisiert, die Benutzeroberfläche jedoch nicht. Ich entschuldige mich für meine Ignoranz (war lange Zeit ein Backend-Entwickler, dies ist mein erster Lauf bei Javascript seit 10 Jahren). Jede Hilfe sehr geschätzt!

Antwort

3

Das Problem ist, dass Sie das ObservableArray nie aktualisieren.

Zunächst rufen Sie den Konstruktor erneut, aber die this Referenz verweist wahrscheinlich nicht auf das Objekt, das Sie denken. Wenn Sie den TweetsViewModel-Konstruktor erneut aufrufen (im setTimeout-Aufruf), verweist der this-Verweis auf das Objekt window.

Selbst wenn Sie die this Referenz erhalten nach rechts Objekt zeigen (was möglich ist, die apply Methode, die Funktionen haben, aber das ist nebensächlich) Sie würden immer noch nicht die observableArray updaten, da Sie einstellen würde die self.tweets Variable auf einen neuen observableArray auf der Linie

self.tweets = ko.observableArray(); 

Alle Abonnements, zB Die UI-DOM-Elemente würden weiterhin dem alten ObservableArray zugeordnet, da sie nicht wissen würden, dass sich die Variable geändert hat.

Also, was Sie sollten wahrscheinlich tun ist, um eine Funktion zu erstellen, die aus den Daten neu geladen ausführt, wie folgt aus:

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

Beachten Sie auch, dass dies immer Tweets zum observableArray hinzufügen würde (nie klar,) und es würde auch dazu führen, dass die Abonnements für das observableArray einmal pro hinzugefügtem Tweet ausgelöst werden. Wenn Sie das Array ersetzen möchten, sollten Sie wahrscheinlich ein Ersatzarray erstellen, Tweets in dieses Array schieben und schließlich das Array im observableArray ersetzen, indem Sie self.tweets(replacementArray); machen.

+0

Vielen Dank. Ich dachte, es könnte so etwas sein, aber ich sah es nicht. Das hat alles aufgeräumt. Ich schätze deine Zeit, mich mit dem Anhaltspunkt zu schlagen. – user3314493

Verwandte Themen