knockout.jsjquery-ui-multiselect

JQuery UI Multiselect with Knockout JS - data-binding with a helper plugin


I'm trying to implement jQuery UI Multiselect with a KnockoutJS binding. I guess it cannot be done natively, which is why this plugin was made.

I'm using the plugin. I create my multiselect in php code but the output html is this:

<select id="multiselectpoc" data-bind="multiselect  : { config : multiSelectConfig,
            options: _categories,
            optionsText: '_name',
            optionsValue: '_id',
            value: selectedCategory,
            optionsCaption: 'CATEGORY'}" title="Basic example" multiple="multiple" name="example-basic" size="5" style="display: none;">
        </select>

I know that creating it in php is not the issue because I create other <select>'s in php that are not jqueryUI Multiselects, and the data-bindings for them work.

Here is my View Model (I use typescript):

class SearchFilterViewModel {
    multiSelectConfig = {};
    _countriesList = [];
    _regionsList = [];
    _countries = ko.observableArray();
    _regions = ko.observableArray();
    _categories = ko.observableArray([
        new Category(name="Meat-Free Meat", 1),
        new Category(name="Dairy-Free Dairy", 2),
        new Category(name="Confectionery", 3),
        new Category(name="Baking", 4),
        new Category(name="Dessert", 5)
    ]);
    selectedCountry = ko.observable();
    selectedCity:  KnockoutObservable<string> = ko.observable('');
    selectedCategory:  KnockoutObservable<string> = ko.observable('');

    constructor(allCountries) {
        for (var index = 0; index < allCountries.length; index++) {
            this._countriesList.push(allCountries[index]);
        }
        this._countries(this._countriesList);
        this.selectedCountry.subscribe(this.updateCities.bind(this))
    }

    updateCities(geonameId) {
        var self = this;
        self._regionsList = [];
        $.ajax({
            url: `http://api.geonames.org/children?geonameId=${geonameId}&username=elion`
        }).then(function(allCitiesXML) {
            var allCitiesJSON = xml2json(allCitiesXML);
            var allCities = JSON.parse(allCitiesJSON);
            for (var index = 1; index < allCities.geonames.length - 1; index++) {
                self._regionsList.push(allCities.geonames[index].geoname);
            }
            self._regions(self._regionsList);
            });
    }
}

class Category {
    _name:  KnockoutObservable<string>;
    _id:    KnockoutObservable<number>;

    constructor(name, id) {
        this._name = ko.observable(name);
        this._id = ko.observable(id);
    }
}



$(document).ready(function() {
    var _searchFilterViewModel: SearchFilterViewModel = new SearchFilterViewModel(allCountries);
    var _searchFilterForm = $("#find-vegan-products-page").find("form")[0];
    ko.applyBindings(_searchFilterViewModel, _searchFilterForm);
    $('.select-multiple').each(function(i, obj) {
        //obj[i] gets each element inside the div
        $(this).multiselect();
    })
});

This question is mainly about how to configure the empty multiSelectConfig object in the viewmodel. When I run the page in a web browser, the output html in the <select> is now many <li> tags that contain a fair bit of jquery ui multiselect code, but the bit that matters is that inside each <option></option> is <span>[object Object]</span> which is inside each <li> tag. There are the same number of <li> tags as categories, which makes me think the data binding is working. I just need to tap into the [object object] to get the properties (category.name). How do I do that?


Solution

  • You should probably run through the KnockoutJS tutorials. AFAICT you're not currently really using it.

    The binding handler is responsible for calling multiselect(...) on your DOM. You should not be calling it yourself like you are doing now. Instead, you need a view model that passes all information to the custom binding handler.

    The binding handler expects a config as input, and your view is telling it that your view model has a multiSelectConfig property that contains that info. The binding handler probably crashes because your view model lacks that property.

    Put differently, the binding handler you have assumes your view models has observables (or at least properties) named:

    You haven't shown your view model code or KO bootstrapping code, but you'll need that to get things running. For example:

    $(function(){
        var vm = {
            multiSelectConfig: { /* config here */ },
            _categories: [{_id: 1, _name: "test"},
            selectedCategory: ko.observable()
        };
        ko.applyBindings(vm);
    });
    

    This code glances over a lot of important concepts, e.g. constructor functions for view models, observable arrays, mapping your json to the view model, etc., so again I recommend checking out the KO website and its tutorials.