Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery Chosen doesn't update select options while working with knockout js

I am trying to make jQuery Chosen and KnockoutJS work at the same time.

The problem is "jQuery Chosen" refuses to update options list even though I've created custom binding for it.

Here is the example - http://jsfiddle.net/5fGAf/

I have two changeable selects - "Country" and "Method". "Method" options list depends on country selected. When I select the country for the first time - everything works perfect. But when I want to change the country - "Method" options list remains the same, even though corresponding knockout computed value is updated.

If I manually run $(".chosen-select").trigger('chosen:updated') in the browser console - options list updates.

Custom binding code:

ko.bindingHandlers.chosen = {
  init: function(element) {             
    $(element).chosen({disable_search_threshold: 10});
  },
  update: function(element) {
    $(".chosen-select").trigger('chosen:updated');
  }
};
like image 250
eawer Avatar asked Feb 25 '14 17:02

eawer


People also ask

Does knockout use jQuery?

It works without jQuery, Prototype. js, or any other JavaScript library, and it is compatible with all popular web browsers, such as Chrome, Firefox, Safari, Internet Explorer and Opera. Knockout provides great documentation, amazing real-time tutorials and many live examples with source code.

Is knockout js easy?

KnockoutJS library provides an easy and clean way to handle complex data-driven interfaces. One can create self-updating UIs for Javascript objects. It is pure JavaScript Library and works with any web framework. It's not a replacement of JQuery but can work as a supplement providing smart features.

Why knockout JS is used?

Knockout. js is a minimalist JavaScript framework for web application development. It is a JavaScript library that allows binding HTML elements against any data model. It is primarily used for creating rich and responsive display as well as editor user interfaces with a clean, underlying data model.


3 Answers

You have two problems:

  • in your fiddle there is no .chosen-select so your update function does not find the select but anyway you should use $(element) to access the currently bound element
  • in KO 3.0 bindings are fired independently. Because your chosen binding is not connected to the your observable array your update won't fire when you change that array.

You can solve this "update" problem with explicitly declaring a dependency on the options binding in your custom binding but a better solution would be to delegate to it:

ko.bindingHandlers.chosen = {
    init: function(element)  {
        ko.bindingHandlers.options.init(element);
        $(element).chosen({disable_search_threshold: 10});
    },
    update: function(element, valueAccessor, allBindings) {
        ko.bindingHandlers.options.update(element, valueAccessor, allBindings);
        $(element).trigger('chosen:updated');
    }
};

And use it where you would normally use the options binding:

<select id="option1" class="form-control" 
    data-bind="chosen: payoutOptions, 
               optionsText: 'optionText', 
               optionsValue: 'optionValue', 
               value: activePayoutOption"></select>

Demo JSFiddle.

like image 136
nemesv Avatar answered Nov 15 '22 20:11

nemesv


My solution is this:

ko.bindingHandlers.chosen =
{
    init: function (element, valueAccessor, allBindings) {
        $(element).chosen(valueAccessor());

        // trigger chosen:updated event when the bound value or options changes

        $.each('value|selectedOptions|options'.split("|"), function (i, e) {
            var bv = allBindings.get(e);
            if (ko.isObservable(bv))
                bv.subscribe(function () { $(element).trigger('chosen:updated'); });
        });
    },
    update: function (element) {
        $(element).trigger('chosen:updated');
    }
};

You'd use it like so:

<select data-bind="
    options: payoutOptions, 
    optionsText: 'optionText', 
    optionsValue: 'optionValue',
    value: activePayoutOption,
    chosen: { disable_search_threshold: 10, width:'100%' }">
</select>

Note that

  1. The chosen binding is option is added...rather than changing the way the given binding works
  2. Chosen options ({ width:'100%',... }) are not hardwired in the handler
like image 35
Duoc Tran Avatar answered Nov 15 '22 20:11

Duoc Tran


I used a method that is also compatible with all my existing bindings, so I didn't need to go though a ton of html files removing the options binding.

ko.bindingHandlers.chosen = {
    init: function(element, valueAccessor, allBindings) {
        $(element).chosen({ disable_search_threshold: 10});
        var valueObservable = allBindings.get('value');
        var optionsObservable = allBindings.get('options');

        var updateList = function() {
            $(element).trigger('chosen:updated');
        }

        if (valueObservable && typeof(valueObservable.subscribe) == 'function') {
            valueObservable.subscribe(updateList);
        }

        if (optionsObservable && typeof(optionsObservable.subscribe) == 'function') {
            optionsObservable.subscribe(updateList);
        }

        $(element).chosen({ disable_search_threshold: 7, width:'100%' });
    }
};
like image 43
aaberg Avatar answered Nov 15 '22 20:11

aaberg