Changes in the igCombo and its extension for the KnockoutJS

Nikolay Alipiev / Monday, December 15, 2014

With the current Service Release (build numbers – 13.2.20132.2417, 14.1.20141.2558, 14.2.20142.2140), our KnockoutJS extension for the igCombo, along with the igCombo control itself, were updated to meet some of the KnockoutJS requirements that was problematic before and to improve some other parts of the extension. In most of the cases these improvements will not affect your current applications and will give you access to new functionalities. In some others cases you will need to update a couple of lines, but we hope this will improve the overall quality your projects.

The sample below, will demonstrate, how the use the current implementation of the KnockoutJS extension of the igCombo. For your ease, the code examples will be accompanied with proper explanations.

Below you can find the Model, ViewModel and the View that we are going to use in this topic:

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4.     <meta charset="utf-8" />
  5.     <title>igCombo KnockoutJS</title>
  6.     <script type="text/javascript">
  7.     $(function () {
  8.         "use strict"
  9.  
  10.         var ds1 = [{ value: 0, name: 'Paul' }, { value: 1, name: 'Andreas' }, { value: 2, name: 'Stefan' }],
  11.             combo = $("#combo"), globalModel;
  12.  
  13.         function ViewModel() {
  14.             var self = this;
  15.  
  16.             this.data = ko.observableArray(ds1);
  17.             ds1[1].name = ko.observable(ds1[1].name);
  18.             ds1[2].name = ko.observable(ds1[2].name);
  19.             this.text = ko.observable("Andreas");
  20.             this.selectedItems = ko.observableArray([{ index: 1 }]);
  21.  
  22.             this.editViewModel = function () {
  23.                 self.data()[1].name("AndreaViewModel");
  24.             }
  25.             this.editDataSource = function () {
  26.                 $("#combo").igCombo("getData")[1].data().name("AndreaDataSource");
  27.             }
  28.             this.editSelectedItem = function () {
  29.                 $("#combo").igCombo("option", "selectedItems")[0].data().name("AndreaSelected");
  30.             }
  31.         }
  32.         ko.applyBindings(globalModel = new ViewModel());
  33.  
  34.         combo.on("igcomboselectionchanging", function (evt, ui) {
  35.             // Get the previously and currently selected items' values
  36.             selectingItems = ui.items[0].data().name();
  37.             oldItems = ui.oldItems[0].data().name();
  38.  
  39.             // Set the previously and currently selected items' values
  40.             ui.items[0].data().name("Paola");
  41.             ui.oldItems[0].data().name("Andrea");
  42.         });
  43.         combo.on("igcomboselectionchanged", function (evt, ui) {
  44.             // Get the currently selected item's values
  45.             selectingItems = ui.items[0].data().name();
  46.  
  47.             // Set the currently selected item's values
  48.             ui.items[0].data().name("Paola");
  49.         });
  50.     });
  51.     </script>
  52. </head>
  53. <body>
  54.  
  55. <input type="text" id="combo"
  56.     data-bind="igCombo:
  57.     {
  58.         text: text,
  59.         dataSource: data,
  60.         textKey: 'name',
  61.         valueKey: 'value',
  62.         allowCustomValue: true,
  63.         selectedItems: selectedItems,
  64.         multiSelection: 'onWithCheckboxes',
  65.         mode: 'editable'
  66.     }" />
  67. <button id="editViewModel" data-bind="click: editViewModel">Edit from the View Model</button>
  68. <button id="editDataSource" data-bind="click: editDataSource">Edit from the igCombo data source</button>
  69. <button id="editSelectedItem" data-bind="click: editSelectedItem">Edit from the igCombo selected items</button>
  70. </body>
  71. </html>

Removing ‘value’ option and making igCombo ‘selectedItems’ option an observable

The ‘value’ option was not initially added to the igCombo KnockoutJS extension. It was added at a later stage, to meet the requirements for some of our clients. The idea of having such an option, was to be able to make the igCombo value observable, instead of the igCombo text. Now it is replaced with the ‘selectedItems’ option, which covers the same requirement for having observable of the combo current value. Here are listed the weaknesses of the previous approach:

  1. There isn’t a real igCombo ‘value’ property, and it was used only by the KnockoutJS extension. This leaded to inconsistency between the extension and the control itself.

     2.  Multiple selection cannot be done using the ‘value’ property.

The 'value' igCombo KnockoutJS option is removed:

  1. <span id="combo" data-bind="igCombo: {
  2.     value: vmValue,
  3.     dataSource: data,
  4.     textKey: 'name',
  5.     valueKey: 'value'
  6. }"></span>

The 'selectedItems' option is introduced and it can be defined as an observable array in the ViewModel object:

  1. function ViewModel() {
  2.     this.selectedItems = ko.observableArray([{ index: 1 }]);
  3. }

         

And then inside the View, the combo ‘selectedItems’ option is bound to the corresponding           ViewModel property.

  1. <span id="combo" data-bind="igCombo: {
  2.     selectedItems: selectedItems,
  3.     dataSource: data,
  4.     textKey: 'name',
  5.     valueKey: 'value'
  6. }"></span>

What we achieve introducing such a change is:

  1. Consistency between knockout extension and igCombo widget. The 'selectedItems' is a igCombo option.
  2. We can make multiple selection, using item value or item index. One of the ways to achieve this is by adding the new selected item to the array of the selected items:
  1. globalModel.selectingItems.push({ index: 3 });

     3.   We are following the KnockoutJS standard of doing selection in the HTML select element - option binding.

igCombo holds references to data and selected data

With the new changes in the igCombo extension, now igCombo holds reference to the data that the igCombo control is bound to. This was not valid before, because the KnockoutJS extension was unwrapping the observable data source, and if a changed occurred, then the entire data source was rebounded. This is improved now and the KnockoutJS extension is passing the data source as a reference to the igCombo control. In a similar manner it also holds reference to the array if the igCombo with the selected items data, one or more depending on the selection type.

Now the igCombo serve as an observer for observable collections. All ViewModel properties that are defined as observables or have observable values, are preserved by the combo in this state. This allows the following functionalities:

  1. Access and change data items through combo API and get their reference – see the 'editDataSource' method in the ViewModel.
  2. Access and change selected items through combo API and get their reference – see the 'editSelectedItem' method in the ViewModel.
  3. Access data items through combo events arguments and get their reference. See the ‘selectionChanging’ and ‘selectionChanged’ events
  1. function ViewModel() {
  2.     ...
  3.     this.editViewModel = function () {
  4.         self.data()[1].name("AndreaViewModel");
  5.     }
  6.     this.editDataSource = function () {
  7.         $("#combo").igCombo("getData")[1].data().name("AndreaDataSource");
  8.     }
  9.     this.editSelectedItem = function () {
  10.         $("#combo").igCombo("option", "selectedItems")[0].data().name("AndreaSelected");
  11.     }
  12. }
  13. ...
  14. combo.on("igcomboselectionchanging", function (evt, ui) {
  15.     // Get the previously and currently selected items' values
  16.     selectingItems = ui.items[0].data().name();
  17.     oldItems = ui.oldItems[0].data().name();
  18.  
  19.     // Set the previously and currently selected items' values
  20.     ui.items[0].data().name("Paola");
  21.     ui.oldItems[0].data().name("Andrea");
  22. });
  23. combo.on("igcomboselectionchanged", function (evt, ui) {
  24.     // Get the currently selected item's values
  25.     selectingItems = ui.items[0].data().name();
  26.  
  27.     // Set the currently selected item's values
  28.     ui.items[0].data().name("Paola");
  29. });

This means that if we change a member in the underlying data source, then the igCombo should react to those changes by updating the values it displays. This means that the list of data members should be updated any time an external update happens. It doesn’t matter if it is changed using the combo methods, or the change happens during some of the combo events.

When ViewModel value is changed, igCombo KnockoutJS extension cannot modify that value

This improvement is something you may never have the chance to experience, because it is related to the case, where we have more than one combo controls on the page. At the same time, one of the combo controls, on that page, should not allow custom values. This means that if we try to set a text of such a combo, and the value is not presented in the list, then combo will set as a text empty string. So if we have several combo controls, and one of them doesn’t allow such a value and we try to change it from the ViewModel, then the combo was updating back the ViewModel with empty string. The idea was to have consistency between all the igCombo controls that are pointing to the same property from the ViewModel. But if a new value is set, using the ViewModel, then it is expected that it will not be changed by anything. That’s why we decided to remove this and leave the value of the ViewModel untouched. If a certain combo doesn’t allow such a value, its text is set to empty string, but not for the others that allow it, or just allow custom values.

Other improvements

Another improvement that we’ve made, an internal one that will not affect your existing code, was to separate the input KnockoutJS binding from the bindings for the combo drop down. This is performance improvement that allows to separate the execution for the different igCombo KnockoutJS logic. For example, when the igCombo text is changed, then the logic for the drop down is not executed, which was the case before.

Including also the usual bug fixes, now this summarizes the changes introduced in the igCombo and its KnockoutJS extension. Changes that you need to be aware of and if needed - apply in your applications.