Extending MultiSelect to Capture Paste Event

6 posts, 0 answers
  1. R J
    R J avatar
    4 posts
    Member since:
    Jul 2015

    Posted 02 Dec 2015 Link to this post

    Hello!

    I wish to add functionality to the MultiSelect in order to capture the "paste" event, parse the input and if any values in the pasted input match are options to the MutliSelect, select them.

    Below is the code I used to extend the MutliSelect.  The parsingMutliSelect.value(...) call is indeed changing the values, however the UI is not updating and displaying the values as tags within the input field for the MultiSelect.  In fact, the error "TypeError: Argument 1 of Node.removeChild is not an object" keeps occurring when the parsingMultiSelect._change() call is made.  This error occurs at the line "tagList[0].removeChild(tagList[0].children[removedItem.position]);" within the _selectValue function definition within the MultiSelect configuration (kendo.multiselect.js).

    Using my FireBug console, I can successfully get the MutliSelect to perform as expected by using the .value() and .trigger("change") methods on the MultiSelect instance.  Why can I not seem to successfully set values from within the MutliSelect extension definition?

     

    01.(function ($) {
    02. 
    03.  var kendo = window.kendo,
    04.      ui = kendo.ui,
    05.      MultiSelect = ui.MultiSelect,
    06.      CHANGE = "change",
    07.      PASTE = "paste";
    08. 
    09.  var ParsingMultiSelect = MultiSelect.extend({
    10. 
    11.    init: function (element, options) {
    12.      var that = this;
    13. 
    14.      // Base call to MultiSelect to initialize ParsingMultiSelect
    15.      MultiSelect.fn.init.call(that, element, options);
    16. 
    17.      that.input.on(PASTE, that, that._paste);
    18.    },
    19. 
    20.    options: {
    21.      // Assigns the name as it should appear off the kendo namespace (i.e. kendo.ui.ParsingMultiSelect).
    22.      // The jQuery plugin would be jQuery.fn.kendoParsingMultiSelect
    23.      name: "ParsingMultiSelect"
    24.    },
    25. 
    26.    events: [
    27.      PASTE
    28.    ],
    29. 
    30.    _paste: function (e) {
    31.      alert("data pasted!");
    32.      var parsingMultiSelect = e.data,
    33.        dataValueField = parsingMultiSelect.options.dataValueField,
    34.        parsingMultiSelectDataSource = parsingMultiSelect.dataSource,
    35.        pastedData = e.originalEvent.clipboardData.getData('text'),
    36.        validValues = [];
    37. 
    38.      multiSelect._close();
    39. 
    40.      parsingMultiSelectDataSource.fetch().done(function () {
    41.        var dataSourceData = parsingMultiSelectDataSource.data();
    42.        var dataSourceValues = [];
    43. 
    44.        if (dataSourceData instanceof kendo.data.ObservableArray) {
    45.          dataSourceValues = dataSourceData.map(function (arrayElement, index) {
    46.            return arrayElement[dataValueField];
    47.          });
    48.        }
    49. 
    50.        // Convert all commas to a single space then reduce all whitespace (and consecutive)
    51.        // characters in the pasted input to a single space to get ready for splitting
    52.        pastedData = pastedData.replace(/,/g, "").replace(/\s\s+/g, " ").trim();
    53. 
    54.        pastedValues = pastedData.split(" ");
    55. 
    56.        // Loop through the values pasted in.  If any exist in the dataSource, push them to
    57.        // the array of valid values.
    58.        $.each(pastedValues, function (index, value) {
    59.          if (dataSourceValues.indexOf(value) != -1) {
    60.            validValues.push(value);
    61.          }
    62.        });
    63. 
    64.        parsingMultiSelect.value(e.data.value().concat(validValues));
    65.        parsingMultiSelect._change();
    66.      });
    67. 
    68.      e.preventDefault();
    69.    }
    70.  });
    71. 
    72.  // Add the ParsingMultiSelect to Kendo UI
    73.  ui.plugin(ParsingMultiSelect);
    74. 
    75.})(jQuery);
    76. 
    77. 
    78.$("#parsingmultiselect").kendoParsingMultiSelect({
    79.  dataSource: [
    80.    { unitId: "0001X" },
    81.    { unitId: "0002X" },
    82.    { unitId: "0003X" },
    83.    { unitId: "0004X" },
    84.    { unitId: "0005X" },
    85.    { unitId: "0006X" }
    86.  ],
    87.  dataTextField: "unitId",
    88.  dataValueField: "unitId",
    89.  placeholder: "Select a Unit ID..."
    90.});

    ...and a jsFiddle: https://jsfiddle.net/Lvvwzmyv/3/.  Try pasting a single value: "0002X" and try pasting multiple values: "0002X, 0004X, 0005X" and observe the unintended behaviour.

     

    Thank you,

    R. J.

  2. R J
    R J avatar
    4 posts
    Member since:
    Jul 2015

    Posted 02 Dec 2015 Link to this post

    Please disregard lines 76-90 in the code block of my previous post.  That was a direct cut-and-paste from jsFiddle and I did not mean to include it.  Lines 1-75 are what I use to extend the MutliSelect.

    Thank you,

    R. J.

  3. Kendo UI is VS 2017 Ready
  4. Konstantin Dikov
    Admin
    Konstantin Dikov avatar
    1796 posts

    Posted 04 Dec 2015 Link to this post

    Hello,

    As documented in the following help article, the value method of the MultiSelect accepts a string value or an array of string value:

    With that in mind, please pass the validvalues array directly to the value method and you will get the desired result:
    //multiSelect._close(); this line is throwing an error in your example, so I have commented it
    ...
    parsingMultiSelect.value(validValues);

    Hope this helps.


    Regards,
    Konstantin Dikov
    Telerik
     
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
     
  5. R J
    R J avatar
    4 posts
    Member since:
    Jul 2015

    Posted 04 Dec 2015 in reply to Konstantin Dikov Link to this post

    Konstantin -

    Thank you for your response.  I am indeed passing an array of strings directly into the value() function.  That is what e.data.value().concat(validValues) produces.  It's an array of the current values of the MultiSelect appended with the pasted (valid) values (which then, of course, gets normalized within the labyrinth of function calls internal to the MultiSelect).

    I'm experiencing very different results with version 2 of the Fiddle (I included version 3 above).  Version 2 seems to actually work using FireFox, however does NOT work in IE.  This may be because of the use of clipboardData as it's not cross-browser supported.  I'll work that issue once I get the behavior of internally setting the value of the MultiSelect consistent.  My actual code is an MVVM implementation (which I could not reproduce exactly in the Fiddle).  I'm suspecting much of the behavior issues related to setting the value has to do with this.  I'll continue to work from your Create a Custom UI Widget page to see if I can get my extended version of your MutliSelect MVVM-aware and working.

    Again, thank you for your response.

    R. J.

  6. R J
    R J avatar
    4 posts
    Member since:
    Jul 2015

    Posted 04 Dec 2015 Link to this post

    ...then again, all MVVM-aware features such as the dataBinding and dataBound events as well as setDataSource() are all still accessible to ParsingMultiSelect from the extended (underlying) MutliSelect.

    Hmmm.........

  7. Konstantin Dikov
    Admin
    Konstantin Dikov avatar
    1796 posts

    Posted 08 Dec 2015 Link to this post

    Hi,

    Indeed, your code for setting the value was correct and the only problem was due to the following line, which is throwing an error in your initial example:
    //multiSelect._close();

    Here is a the working code:
    (function ($) {
     
      var kendo = window.kendo,
          ui = kendo.ui,
          MultiSelect = ui.MultiSelect,
          CHANGE = "change",
          PASTE = "paste";
     
      var ParsingMultiSelect = MultiSelect.extend({
     
        init: function (element, options) {
          var that = this;
     
          // Base call to MultiSelect to initialize ParsingMultiSelect
          MultiSelect.fn.init.call(that, element, options);
     
          that.input.on(PASTE, that, that._paste);
        },
     
        options: {
          // Assigns the name as it should appear off the kendo namespace (i.e. kendo.ui.ParsingMultiSelect).
          // The jQuery plugin would be jQuery.fn.kendoParsingMultiSelect
          name: "ParsingMultiSelect"
        },
     
        events: [
          PASTE
        ],
     
        _paste: function (e) {
          alert("data pasted!");
          var parsingMultiSelect = e.data,
              dataValueField = parsingMultiSelect.options.dataValueField,
              parsingMultiSelectDataSource = parsingMultiSelect.dataSource,
              pastedData = e.originalEvent.clipboardData.getData('text'),
              validValues = [];
     
          //e.sender._close();
     
          parsingMultiSelectDataSource.fetch().done(function () {
            var dataSourceData = parsingMultiSelectDataSource.data();
            var dataSourceValues = [];
     
            if (dataSourceData instanceof kendo.data.ObservableArray) {
              dataSourceValues = dataSourceData.map(function (arrayElement, index) {
                return arrayElement[dataValueField];
              });
            }
     
            // Convert all commas to a single space then reduce all whitespace (and consecutive)
            // characters in the pasted input to a single space to get ready for splitting
            pastedData = pastedData.replace(/,/g, "").replace(/\s\s+/g, " ").trim();
     
            pastedValues = pastedData.split(" ");
     
            // Loop through the values pasted in.  If any exist in the dataSource, push them to
            // the array of valid values.
            $.each(pastedValues, function (index, value) {
              if (dataSourceValues.indexOf(value) != -1) {
                validValues.push(value);
              }
            });
    debugger;
            parsingMultiSelect.value(e.data.value().concat(validValues));
            parsingMultiSelect._change();
            parsingMultiSelect.close();
          });
     
          e.preventDefault();
        }
      });
     
      // Add the ParsingMultiSelect to Kendo UI
      ui.plugin(ParsingMultiSelect);
     
    })(jQuery);
     
     
    $("#parsingmultiselect").kendoParsingMultiSelect({
      dataSource: [
        { unitId: "0001X" },
        { unitId: "0002X" },
        { unitId: "0003X" },
        { unitId: "0004X" },
        { unitId: "0005X" },
        { unitId: "0006X" }
      ],
      dataTextField: "unitId",
      dataValueField: "unitId",
      placeholder: "Select a Unit ID..."
    });



    Regards,
    Konstantin Dikov
    Telerik
     
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
     
Back to Top
Kendo UI is VS 2017 Ready