Search code examples
javascriptjquerykendo-uikendo-autocomplete

Kendo UI Autocomplete And Multi Select server side filter set value using JavaScript


I am using Kendo UI controls KendoUI Autocomplete & KendoUI MultiSelect. I need to change those control values & its display programmatically on client side without user acting on those controls.

How to reproduce the behavior:

  1. Please look at this JS fiddle link, there are two Autocomplete controls.
  2. Please type couple of characters in each control and select a result from auto suggestions.
  3. Then click on on Reverse button, JS attempts to change (reverse) values, but that will no complete, without user clicking on the result populated on the auto suggest.

How can I avoid user selecting the results? If user clicks on Reveres both controls should have new selected values and its display should reflect it as well. If I click on Show Selection, that should show new selected values? I have similar issue with MultiSelect as well, If believe if I get this solved, same solution would be applicable for MultiSelect as well.

HTML

<div class="demo-section k-content">
  <h4>Find a product</h4>
  <input id="From" style="width: 100%;" placeholder="From" />
  <div class="demo-hint">Hint: type "che"</div>
  <br />
  <input id="To" style="width: 100%;" placeholder="To" />
  <div class="demo-hint">Hint: type "unc"</div>
  <br />
  <p>Please select From and To then clcik on reverse</p>
  <button id="reverse">
    Reverse
  </button>
  <button id="show">
    Show Selection
  </button>
  <p id="result">

  </p>
</div>

JS

 $(document).ready(function() {
   $("#result").html("");
   $("#From").kendoAutoComplete({
     dataTextField: "ProductName",
     filter: "contains",
     minLength: 2,
     dataSource: {
       type: "odata",
       serverFiltering: true,
       transport: {
         read: "https://demos.telerik.com/kendo-ui/service/Northwind.svc/Products"
       }
     }
   });
   $("#To").kendoAutoComplete({
     dataTextField: "ProductName",
     filter: "contains",
     minLength: 2,
     dataSource: {
       type: "odata",
       serverFiltering: true,
       transport: {
         read: "https://demos.telerik.com/kendo-ui/service/Northwind.svc/Products"
       }
     }
   });

   $("#reverse").click(function(e) {
     $("#result").html("");
     var $departure = $("#From").data("kendoAutoComplete");
     var $destination = $("#To").data("kendoAutoComplete");

     var departureStation = $departure.dataItem();
     var destinationStation = $destination.dataItem();

     $departure.search(destinationStation.icao_id);
     $departure.select($departure.ul.children().eq(0));
     $departure.value(destinationStation.DisplayName);
     $departure.trigger("change");
     $departure.close();

     $destination.search(departureStation.icao_id);
     $destination.select($destination.ul.children().eq(0));
     $destination.value(departureStation.DisplayName);
     $destination.trigger("change");
     $destination.close();

   });

   $("#show").click(function(e) {
     $("#result").html("");
     var $departure = $("#From").data("kendoAutoComplete");
     var $destination = $("#To").data("kendoAutoComplete");

     var departureStation = $departure.dataItem();
     var destinationStation = $destination.dataItem();
     var from = JSON.stringify(departureStation);
     var to = JSON.stringify(destinationStation);
     $("#result").html("From :" + from + "<br/><br/><br/><br/>To: " + to);
   });
 });

Solution

  • One main issue is that you have serverFiltering: true and asynchronous activity is happening.

    The search method will cause a filter to be applied to the dataSource, which in turn causes a server interaction that will fire event dataBound upon completion.

    A kendoAutoComplete opens its drop down during typing and will leave it open while additional filtering (implicit searching) occurs for each new keystroke.

    Solution:

    • Install dataBound event handlers that check if the swap action was forced, and if so automatically select the first drop down item.
    • Use ready-function-scoped flag variables to indicate swapping is happening
    • Swap click handler will:
      • Set the flag variables
      • Invoke programmatic search
        • From docs, search will collaterally open the DDL.
      • dataBound handlers:
        • force DDL selection because flag is active.
        • close DDL
        • trigger change
        • toggle flag variable off

    JS from this Dojo

     $(document).ready(function() {
    
       $("#From").kendoAutoComplete({
         dataTextField: "ProductName",
         filter: "contains",
         minLength: 2,
         dataBound: function(e) { swap1() },
         dataSource: {
           type: "odata",
           serverFiltering: true,
           transport: {
             read: "https://demos.telerik.com/kendo-ui/service/Northwind.svc/Products"
           }
         }
       });
    
       $("#To").kendoAutoComplete({
         dataTextField: "ProductName",
         filter: "contains",
         minLength: 2,
         dataBound: function(e) { swap2() },
         dataSource: {
           type: "odata",
           serverFiltering: true,
           transport: {
             read: "https://demos.telerik.com/kendo-ui/service/Northwind.svc/Products"
           }
         }
       });
    
       var one_swapping = false;
       var two_swapping = false;
    
       function swap1() {
         if (one_swapping) {
           var ac = $("#From").data('kendoAutoComplete');
           ac.select(ac.ul.children().eq(0));
           ac.close();
           ac.trigger("change");
           one_swapping = false;
         }
       }
    
       function swap2() {
         if (two_swapping) {
           var ac = $("#To").data('kendoAutoComplete');
           ac.select(ac.ul.children().eq(0));
           ac.close();
           ac.trigger("change");
           two_swapping = false;
         }
       }
    
       $("#swap").click(function(e) {
         $("#result").html("");     
    
         var one = $("#From").data("kendoAutoComplete");
         var two = $("#To").data("kendoAutoComplete");
    
         var one_val = one.element.val();
         var two_val = two.element.val();
    
         one_swapping = true;
         one.search(two_val);  // force the filter 
    
         two_swapping = true;
         two.search(one_val);  // force the filter
       });
    
       $("#show").click(function(e) {
         $("#result").html("");
         var $departure = $("#From").data("kendoAutoComplete");
         var $destination = $("#To").data("kendoAutoComplete");
    
         var departureStation = $departure.dataItem();
         var destinationStation = $destination.dataItem();
         var from = JSON.stringify(departureStation);
         var to = JSON.stringify(destinationStation);
         $("#result").html("From :" + from + "<br/><br/><br/><br/>To: " + to);
       });
     });