arb
arb

Reputation: 7863

Knockout.JS Observable Array via AJAX bound to DropDownList

I am trying to fill my view model with some drop down options from the database. I want to keep track of the selected object because it has properties on it that I am using in a custom binding elsewhere.

I initialize the observable with a "blank" value so that it's properly set when the binding occurs and my custom binding works. Once the server responds, I morph the data to an observable array and the drop down list displays the options.

Here is the JavaScript code:

ko.bindingHandlers.jq_fade = {
    init: function (element, valueAccessor) {
        // Initially set the element to be instantly visible/hidden depending on the value
        var value = valueAccessor();
        $(element).toggle(ko.utils.unwrapObservable(value)); // Use "unwrapObservable" so we can handle values that may or may not be observable
    },
    update: function (element, valueAccessor) {
        // Whenever the value subsequently changes, slowly fade the element in or out
        var value = valueAccessor();
        ko.utils.unwrapObservable(value) ? $(element).fadeIn() : $(element).fadeOut();
    }
};

function Firm(id, name, outsideCounsel) {
    this.name = name;
    this.id = id;
    this.outsideCounsel = outsideCounsel;
}

function RequestViewModel() {
    var self = this,
        ONE_DAY = 1000 * 60 * 60 * 24;


    self.firm = ko.observable(new Firm(-1, "", false));

    $.post(ajaxAddress + 'LoadFirms', function (data) {
        var mappedFirms = $.map(data.d, function (item) {
            return new Firm(item.OrganizationLookupID, item.OrganizationLookupName, item.IsExternalCounselFirm);
        });
        self.availableFirms(mappedFirms);
        self.firm(self.availableFirms()[0]);
    });
}


$(document).ready(function () {
    model = new RequestViewModel();
    ko.applyBindings(model);
});

Here is the relevant HTML

<span data-bind="jq_fade: firm().outsideCounsel">
    Outside Counsel
    <input type="text" id="outsideCounsel" data-bind="value: outsideCounsel" />
</span>

I want that DIV to show only if the selected firm is an outside counsel. If remove the line data-bind="jq_fade: firm().outsideCounsel, everything works fine. If I make the $.post() calls synchronously, it works. I'm thinking it's something wrong with my init function in jq_fade.

The error I receive is:

Uncaught Error: Unable to parse bindings. Message: TypeError: Cannot call method 'outsideCounsel' of undefined; Bindings value: jq_fade: firm().outsideCounsel()

I understand what Knockout is telling me, I'm just not sure how firm() can ever be undefined because I set up an initial value.

Upvotes: 0

Views: 2289

Answers (1)

soniiic
soniiic

Reputation: 2685

If you're binding availableFirms() to a dropdownlist, I'm assuming you've also bound firm() to the same list so that when another is selected from the list, firm() gets automatically updated and all your bindings update automatically.

If this is the case, you do not need to set firm() at all as it will be set to the first element in the dropdownlist anyway.

See example 3 here:

http://knockoutjs.com/documentation/options-binding.html

var viewModel = {
    availableCountries : ko.observableArray([
        new country("UK", 65000000),
        new country("USA", 320000000),
        new country("Sweden", 29000000)
    ]),
    selectedCountry : ko.observable() // Nothing selected by default
};

Try it like above without specifically setting firm() and see if it errors again

Upvotes: 1

Related Questions