1

Currently using msDropDown 3.2 to make controls look pretty, however due to the nature of the application being developed, I have looked into using Knockout JS to handle UI-Data Binding. Unfortunately, whenever I change the property on the view model it is changing the select but not the rendered control (I know the code required to change the rendered control, but am not sure on how to hook this into Knockout).

Has anybody integrated these two tools, and if so then how did you get them to play nicely together?

Edit:

HTML:

<select data-bind="value: Type">
   <option value="1">First</option>
   <option value="2">Second</option>
   <option value="3">Third</option>
   <option value="4">Fourth</option>
</select>

JavaScript:

function ViewModel() {
    var self = this;
    self.Name = ko.observable();
    self.Type = ko.observable();
    self.IsVisible = ko.computed(function () {
        return this.Type() == 1;
    }, this);
}

var vm = new ViewModel();

ko.applyBindings(vm);

$(document).ready(function () {
    $("select").msDropDown();
});

As you can see from the above code, I am creating a ViewModel instance, then applying the bindings and initiating msDropDown.

If I was to then call the following:

vm.Type("2");

Then it will update the underlying select, but not the front end of the msDropDown control. Basically need a way to hook into an event that Knockout may call when changing a property so that I can determine if it's a select and call some msDropDown specific code to update the UI.

Thanks,

Chris.

Irvin Dominin
  • 30,819
  • 9
  • 77
  • 111
Chris
  • 416
  • 2
  • 14

3 Answers3

2

Thanks for all of your answers, however I have managed to find a solution which involved creating my own binder:

ko.bindingHandlers.setValue = {
    init: function (a, b, c) {
        var value = ko.utils.unwrapObservable(b());

        if (typeof value == 'undefined') {
           value = $(a).find("option").first().val();
        }
        $(a).val(value).change(function(){
            var observable = b();
            observable($(this).val());
        }).msDropdown();
    },
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = valueAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(value);
        // Get the value from the observable and set the value on the msDropDown.
        $(element).msDropDown().data("dd").set("value", valueUnwrapped);
    }
};

function ViewModel() {
    var self = this;
    self.Name = ko.observable();
    self.Type = ko.observable();
    self.IsVisible = ko.computed(function () {
        return this.Type() == 1;
    }, this);
}

var vm = new ViewModel();

ko.applyBindings(vm);

Then in the HTML

<select name="myselect" data-bind="setValue: Type">
    <option value="1">1</option>
    <option value="2">2</option
    <option value="3">3</option
    <option value="4">4</option
</select>

This applies the msDropDown plugin to the select, and whenever the viewmodel changes it updates the underlying select and the UI elements generated by msDropDown. Also, when updating the selected item in the UI it persists back to the viewmodel.

Thanks for all your help, and hopefully others who are attempting to use Knockout JS along with msDropDown will find this helpful.

Chris.

Chris
  • 416
  • 2
  • 14
1

As MarcoK says, you'll need to subscribe to the change

I assume that you won't be using a static drop down (I may be wrong)
In this case, you can also use the afterAdd binding in your UI to call your updateUI method - Basically ensuring that after each item is added, the updateUI function is called (re-applying the msDropDown() so that your items are displayed correctly

function ViewModel() {
    var self = this;
    self.Name = ko.observable();
    self.Type = ko.observable();
    self.IsVisible = ko.computed(function () {
        return this.Type() == 1;
    }, this);

    self.updateUI = function(){
        $("select").msDropDown();
    }

    self.Type.subscribe(function(newValue) {
        updateUI();
    });

    //just added this as I assume you will be using a generated options list
    self.myOptions = ko.observableArray();
}

And your markup becomes:

<select data-bind="value: Type, options: myOptions, afterAdd: updateUI">
</select>

More info on template binding: http://knockoutjs.com/documentation/template-binding.html

Alex
  • 37,502
  • 51
  • 204
  • 332
  • That's great, thanks. But how would I get the instance of the - so I can't just do $("select").msDropDown(), you have to explicitly target an instance and set the value - $("#MyDropDown").msDropDown().data("dd").set("value", newValue) – Chris Dec 10 '12 at 14:13
0

To create the hook, you subscribe to the observable (inside your VM):

self.Type.subscribe(function(newValue) {
    // Use "newValue" to read the new value, which you can use
    // to bind to msDropDown / the UI
});
MarcoK
  • 6,090
  • 2
  • 28
  • 40