3

I have a scenario where I have access to a Select control (Combobox) and I need a way to fire an event when its source / options list changes.

For example, if I have a select control which first has Option1 and Option2 as its options, I need a way to fire an event when the options change to Option1, Option3, Option4. I dont care if a new option was added, deleted or if all the items are newly added. All I want is a event handler when the options of a select control change.

One of the friends suggested DOM changed as Option elements get added to DOM, but I am not sure of it as DOM changed gets fired everytime ANY dom element in the page changed.

Update: Sorry about the confusion. I am not looking for selection change. I am looking for the change of actual list of options.

I am using Knockoutjs and I am binding an observable array to a select control as options. knockoutjs's applybindings takes a few milliseconds and then sets the observable array as the options of Select control. I need to have a hook to that change event so that I can do something based on the new set of options.

Before someone says why not handle change of observable array, I do not have access to that observable array at the location I have the event handler.

Update 2:

Here is more info.

I have a select control to which have a custombinding, something like this.

 @Html.KnockOutDropDownListFor(rule => ruleTemplate.RuleReserveWordId, new List<SelectListItem>(), null,
              new {data_bind = "options: $root.RuleReserveWords, optionsText:'Name', optionsValue:'RuleReserveWordId', typeaheadCombobox: {sizeClass : 'input-mini'}" }

@Html.KnockoutDropDownlIstFor is a custom ASP.NET MVC helper I wrote to create a select control with al lthe appropriate knockout related attributes. It eventually renders a select control to the DOM.

The select control I want is supposed to be a autocomplete/typeahead comobox. And since we are using bootstrap, we used a bootstrap plugin from here

https://github.com/danielfarrell/bootstrap-combobox

In my custom binding, I tried to call the plugin.

selectControl.customcombobox();

The plugin basically creates an input control over the select control and hides the select control. At the same time, it tries to access the options of the select control and sets as a dropdown menu for the input control as users start typing.

The problem is since I call ko.applybindings very very early (becasue I think no matter where I call applybindings, once the bindings are all set, the UI will automatically update), by the time the plugin is called, the bindings are not yet bound. So, the select control doesnt have the actual options set. So, the input control doesnt have any value set.

If I call the plugin after a few milliseconds, it works as the bindings are done by then. But its risky becasue if the server call took longer, things will break again.

That was why I was looking to see if there is a way to find either

1) When the select controls options are updated (from no options to some options after binding) using jquery. There is no way for this directly. Some people suggested using DOM updated but it doesnt work for all browsers and is depracated.

or

2) Find a way in knockout to find out when the actual observablearray bound to the select control is updated (in this example RuleReserveWords). This would be my preferred way.

I cannot use the "update" becasue its called everytime the value selected in select control is changed. This is not what I want.

I have a way to update the options as long as I know when to.

Another way I tried was this. I tried to add the options to select control myself before callign the plugin. The DOM renders fine but somehow the selection is not set right after binding.

ko.bindingHandlers.typeaheadCombobox = {
    init: function (element, valueAccessor, allBindingsAccessor)
    {
        var valueUnwrapped = ko.utils.unwrapObservable(valueAccessor());
        var selectControl = $(element);
        var options = allBindingsAccessor().options;
        var optionsValuePropertyName = allBindingsAccessor().optionsValue;
        var optionsTextPropertyName = allBindingsAccessor().optionsText;
        //Add appropriate class for the typeahead combobox plugin to work
        selectControl.addClass('combobox');
        $.each(options(), function (index, option)
        {
            var value = null;
            var text = null;
            for (var propertyName in option)
            {
                if (propertyName)
                {
                    if (propertyName == optionsValuePropertyName)
                    {
                        value = option[propertyName];
                    }
                    else if (propertyName == optionsTextPropertyName)
                    {
                        text = option[propertyName];
                    }
                }
            }
            if (value && text)
            {
                selectControl.append('<option value=' + value() + '>' + text() + '</option>');
            }
        });
        //Call bootstrap custom combobox plugin on the select control
        selectControl.customcombobox(options());
        //Find the input control that is created by the bootstrap custom combobox plugin to set input control settings like size, style, validation attributes, etc
        var inputControl = selectControl.parent().find('input');
        inputControl.attr('name', selectControl.attr('name'));
        inputControl.attr('data-val', selectControl.attr('data-val'));
        inputControl.attr('data-val-required', selectControl.attr('data-val-required'));
        inputControl.attr('style', selectControl.attr('style'));
        if (inputControl && valueUnwrapped && valueUnwrapped.sizeClass) //Used the sizeClass instead of class itself becasue IE7 was having issues if using class or 'class' for custom bindings.
        {
            inputControl.addClass(valueUnwrapped.sizeClass);
        }        
    }
Krishna Veeramachaneni
  • 2,131
  • 3
  • 18
  • 24
  • 1
    What do you mean by: `its source / options list changes` – hjpotter92 Jan 22 '13 at 22:17
  • I suppose you change the options list using javascript, so you can make a callback, can you add some code? – Tomas Ramirez Sarduy Jan 22 '13 at 22:19
  • Do you mean the selection change in the select control? If so, `onchange` event will be triggered when you change the selection. – Selvakumar Arumugam Jan 22 '13 at 22:19
  • 1
    See this question: http://stackoverflow.com/questions/2844565/is-there-a-jquery-dom-change-listener If I understand you this is what you are looking for – Ivan Jan 22 '13 at 22:56
  • Ivan, thanks for the link. I need this to work for IE7 (I know I know) and that solution works mostly for Chrome and newer versions of IE. Having said that, its a pretty good solution if IE7 worked with that. – Krishna Veeramachaneni Jan 22 '13 at 23:26
  • Could you create a jsFiddle? That would help us just tweak and maybe get it working. – BeaverProj Jan 23 '13 at 00:49
  • Why don't you have access to that observable array? In the worst case you can run `ko.dataFor` or `ko.contextFor` on the – antishok Jan 25 '13 at 13:56
  • antishok...thanks for the response...I have access to the observable array...my issue is how do I know when that observable array is updated. There is a subscribe but its only for an object, not an observablearray. – Krishna Veeramachaneni Jan 25 '13 at 18:08

1 Answers1

0

I am assuming that RuleReserveWords is a knockout observable array? In that case you can subscribe to it. The subscribe should fire when the list changes...

viewModel.RuleReserveWords.subscribe(function() { ... list has changed here... })
Felix
  • 1,205
  • 9
  • 17