dmikester1
dmikester1

Reputation: 1362

dropdown not updating from Knockout array

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.

Upvotes: 0

Views: 279

Answers (2)

adiga
adiga

Reputation: 35222

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

Upvotes: 1

pim
pim

Reputation: 12577

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.

Upvotes: 1

Related Questions