0

I am updating my Knockout object in Knockout and am verifying via the console that it is getting updated correctly. But the dropdown is not getting refreshed with the new value. If I refresh the page manually, the dropdown will be updated. I think I need to make something observable, but not totally sure.

This is my KO viewmodel:

var SellerViewModel = function(groups) {
        var self = this;

        self.json = groups;
        self.groups = ko.computed(function() {
            var opts = [];
            for(var key in self.json)
            {
                if(self.json.hasOwnProperty(key))
                {
                    opts.push({Text: self.json[key].majorGroup + " / " + self.json[key].minorGroup, Value: self.json[key].groupId});
                }
            }
            return opts;
        });

        self.addGroup = function(json) {
            var group = JSON.parse(json);
            self.json.push(
                {
                    "ExtensionData":{},
                    "contractId":"10006",
                    "groupId":group.groupID,
                    "imageId":null,
                    "majorGroup":group.majorGroup,
                    "minorGroup":group.minorGroup
                }
            );
            console.log(JSON.stringify(self.json));
        };

And my HTML dropdown:

<select data-bind="value: roomID, options: $root.groups, optionsValue: 'Value', optionsText: 'Text', optionsCaption: ' -- select a room --', disable: disableRoom" class="form-control" id="@roomID"></select>

And finally, this is how the dropdown gets populated on pageload:

var groups = @Html.Raw( Json.Encode(ViewBag.GroupDetail.SellerGroup) );
sellerViewModel = new SellerViewModel(groups);

Forgot to add one last snippet. This is how I am adding an additional item into the knockout object, which is supposed to update the dropdown.

var json = '{"majorGroup" : "' + major + '", "minorGroup" : "' + minor + '", "groupID" : "' + groupID + '" }';
sellerViewModel.addGroup(json);

My guess is that self.groups needs to be an observable array. But I don't know how to do that because I set it equal to ko.computed already.

dmikester1
  • 1,374
  • 11
  • 55
  • 113

2 Answers2

1

This is a simple problem, with a simpler solution.

self.json = ko.observableArray(groups);

In order for your computed to fire, it needs to register a "subscription". Right now, you have it tied to just a normal JavaScript variable (by the look of the push() I'm guessing it's an array).

Making self.json an observable array will create this subscription for you.

pim
  • 12,019
  • 6
  • 66
  • 69
  • I think you're right. I must have something still not right in my code, my dropdown is getting populated with multiple "undefined / undefined" on page load. I can't see where it is coming from though. That is happening after I added your code from above. – dmikester1 Nov 14 '17 at 21:07
  • What is the result of `console.log(groups);` if you place that as the first line in your view model? – pim Nov 14 '17 at 21:36
1

As @pimbrouwers already mentioned, you need to make json an observableArray if you want the UI updated whenever the array changes.

self.json = ko.observableArray(groups);

You can make some improvements to your code. Instead of looping through indexes of self.json and checking hasOwnProperty, you could use map:

self.groups = ko.computed(function() {
    // if "json" is not an observableArray, then "self.json.map"
    return self.json().map(function(group) {
      return {
        Text: group.majorGroup + " / " + group.minorGroup,
        Value: group.groupId
      }
    })
});

And you are concatenating and forming a json in string format and then parsing it back. Instead, you could send an object itself.

var group = {
  majorGroup: major,
  minorGroup: minor,
  groupID: groupID 
}

sellerViewModel.addGroup(group);

And remove the JSON.parse() from the self.addGroup.


Here's a fiddle for testing with all these changes

You can also go through this answer to know more about the difference between json and javascript object literal

adiga
  • 34,372
  • 9
  • 61
  • 83
  • Thank you. I kept getting those "undefined / undefined" added into my dropdown on pageload. I was checking `self.json().length` right before right before the for loop in the computed function and it was 0, so I don't know why 7 of those were getting added. But when I changed it to your map example above, that issue went away. No idea! – dmikester1 Nov 15 '17 at 15:29
  • @adiga you're completely right... I sincerely apologize, was having a bad morning and there was absolutely no reason to take this out on you. I will remove my previous comments out of respect. I also just want to mention that the rep-side of SA isn't the motivation. I find helping people in this fashion usually leads to a better conceptual understanding for me personally. – pim Nov 15 '17 at 17:53
  • 1
    @pimbrouwers well, we have that in common. I learn a lot of stuff by going through the documentation and reading other answers. This is why I like knockout and asp.net-mvc tags because there aren't many [FGITWs](https://meta.stackexchange.com/questions/18014/what-is-fgitw-and-scite) here to ruin all the fun :) Unlike say, javascript or c#. – adiga Nov 15 '17 at 18:05