Question

Basically, what I am trying to achieve is to populate a dropdown based on the value of another dropdown in Knockout.js

My view code(stripped obviously):

            <div data-bind="with: chosenMailData">
                <table id="tabl-1234" class="mails">
                    <thead><tr><th>Destination</th><th>Hotel</th></tr></thead>
                    <tbody data-bind="template: { name: 'iti-template', foreach: objects, afterRender: $root.myPostProcessingLogic }">
                </table>
            </div>

            <script type="text/html" id="iti-template">
                <tr>
                    <td><select class="desti" data-bind="options: $root.destinations, value: destination.name"></select></td>   
                    <td><select data-bind="options: $root.generall(), value: $root.generall()"></select></td>
                </tr>
            </script>

My View-Model(again stripped-down):

            self.destinations=['Kerela', 'Shoghi, Himachal Pradesh', 'Kasauli, Himachal Pradesh'];

            self.myPostProcessingLogic = function(elements) {
                this.generall = ko.computed(function() {
                    $('.desti').each(function(i, obj) {
                        stayOptions = [];
                            $.getJSON("http://127.0.0.1:8000/api/hotel?format=json&location__name="+obj.value, function(data) {
                                    $.each(data.objects, function(i, item){
                                    stayOptions.push(item.name);
                                    });
                                });
                    });
                    return stayOptions;
                }, this);
            }

Inserting alert() in this.generall() shows that stayOptions does get populated with the values I want in it. It is getting that array to get displayed in select options for corresponding row in Hotels column which is the problem.

Probably I am making a really dumb mistake but I have been looking at the code for a long time now and nothing comes to mind. Please advise.

EDIT: I am doing this too at the beginning of my view-model:

            self.generall = ko.observableArray();
Was it helpful?

Solution

When calling methods, the this variable gets assigned on invocation.

var f = $root.myPostProcessingLogic;
f(); // this will not set 'this' to '$root'

The above is essentially what knockout is doing, and this makes this be bound to something else inside myPostProcessingLogic(). You have already defined the scoped self variable, so this is easy to fix.

Another problem is that, reassigning observables won't preserve any subscribers, and any dependant observables won't update.

self.generall = ko.observableArray();
self.myPostProcessingLogic = function(elements) {
    self.generall.removeAll();
    $('.desti').each(function(i, obj) {
        $.getJSON("http://127.0.0.1:8000/api/hotel?format=json&location__name="+obj.value, function(data) {
            $.each(data.objects, function(i, item){
                self.generall.push(item.name);
            });
        });
    });
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top