Search code examples
ajaxknockout.jsko.observablearray

Merge value from another observableArray into existing observableArray in KnockoutJS


I am having trouble figuring out how to add to a pre-existing observableArray after issuing a second AJAX request for similar, but different data.

My first JSON request does not contain the type called value, so I need to add it. My initial JSON structure:

[{"statusmsg":"OK","data":{"status":"stopped"},"sender":"hostname","statuscode":0}]

A second AJAX request is issued which gets the uptime of a service from the REST server:

[{"statusmsg":"OK","data":{"value":"","fact":"some_fact"},"sender":"hostname","statuscode":0}

I want to add to the nested object data the type value, which contains some_fact.

I have tried the following:

ko.utils.arrayForEach(self.rows(), function(row) {
   ko.utils.arrayForEach(self.timeRows, function(time) {
      if(row.sender() == time.sender()) {
         self.rows()[0].data.push({value: time.data.value()});
      }
   });
});

Note: I am using the placeholder index 0 for testing only. Ideally, I would like to just find the match based on the hostname and update the observableArray.

When this code executes, I receive the error that

TypeError: self.rows(...)[0].data.push is not a function

I also tried putting parentheses next to data like data().push, but that did not work either.

The intent is to add a new value to the original observableArray called rows so I can update my view with the new information.


Solution

  • To solve my problem, I used @Sybeus' answer but then I realized that my rows were not updating in my UI because my UI was bound to the old version of rows. Even when I tried to create a dummy subscriber and notify my computed observable that the rows were updated, it was still bound to the old rows as described in this answer:

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

    So what I had to do was the following:

    self.updateServiceStartTime = function() {
      var url = "url";
    
      $.ajax({
         method: "GET",
         url: url,
         success: function(data) {
            var observableData = ko.mapping.fromJSON(data);
            var array = observableData();
            self.timeRows(array);
    
            ko.utils.arrayForEach(self.rows(), function(row) {
               ko.utils.arrayForEach(self.timeRows(), function(time) {
                  if(row.sender() == time.sender()) {                    
                     if (time.data.value()) {
                        row.data.value = time.data.value;
                     }
                     else {
                        row.data.value = "No time found yet.";
                     }
                  }
               });
            });
            self.cloneRows(self.rows().slice());
            self.rows.removeAll();
            self.rows(self.cloneRows().slice());
         }
      });
      };
    

    This updates the UI with the new data that I added.