Search code examples
javascriptjqueryautocompletematerialize

Two onChange events on Materializecss Autocomplete


Scenario:

I'm using Materializecss autocomplete, when i select an item from the autocomplete box, an onchange event should be triggered.

Code:

<div class="row">
  <div class="col s12">
    <div class="row">
      <div class="input-field col s12">
        <input type="text" id="autocomplete-input" class="autocomplete" onchange="sendItem(this.value)">
        <label for="autocomplete-input">Autocomplete</label>
      </div>
    </div>
  </div>
</div>
<script>
$('input.autocomplete').autocomplete({
  data: {
    "Apple": null,
    "Microsoft": null,
    "Google": 'http://placehold.it/250x250'
  },
  limit: 20, 
});
  function sendItem(val) {
    console.log(val);
  }
</script>

Issue:

When i type "AP" and selects "APPLE" from the autocomplete, i need one onchange event to be triggered passing the value "APPLE" but the above program triggers onchange event twice, one passing "AP" and the next passing "APPLE". How can i trigger the latter event. Any advice would be helpful. Thank you.

here is a working jsfiddle program.


Solution

  • When i type "AP" and selects "APPLE" from the autocomplete, i need one onchange event to be triggered passing the value "APPLE" but the above program triggers onchange event twice, one passing "AP" and the next passing "APPLE".

    That happens because when you click/select a materialize autocomplete element two actions are performed:

    • trigger change event on input field
    • execute the onAutocomplete callback

    But, your onchange inline event handler is executed the first time because you move on the drop down list after pressing AP and after on the autocomplete list element APPLE.

    The involved materialize source code is:

    // Set input value
    $autocomplete.on('click', 'li', function () {
      var text = $(this).text().trim();
      $input.val(text);
      $input.trigger('change');   // your issue.......
      $autocomplete.empty();
      resetCurrentElement();
    
      // Handle onAutocomplete callback.
      if (typeof(options.onAutocomplete) === "function") {
        options.onAutocomplete.call(this, text);
      }
    });
    

    In order to solve your issue you need to:

    • remove the inline onchange="sendItem(this.value)"
    • add the following callback to your autocomplete:

      onAutocomplete: function(txt) {

      sendItem(txt);
      

      },

    In the following the snippet (or fiddle) using this approach:

    function sendItem(val) {
        console.log(val);
    }
    
    $(function () {
        $('input.autocomplete').autocomplete({
            data: {
                "Apple": null,
                "Microsoft": null,
                "Google": 'http://placehold.it/250x250'
            },
            onAutocomplete: function(txt) {
              sendItem(txt);
            },
            limit: 20, // The max amount of results that can be shown at once. Default: Infinity.
        });
    
    });
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/js/materialize.min.js"></script>
    
    
    <div class="row">
        <div class="col s12">
            <div class="row">
                <div class="input-field col s12">
                    <input type="text" id="autocomplete-input" class="autocomplete">
                    <label for="autocomplete-input">Autocomplete</label>
                </div>
            </div>
        </div>
    </div>

    A different approach can be based on the isTrigger property of event object in jQuery. Right because the second onchange event is triggered from jQuery you can test against this value:

    function sendItem(val, e) {
        if (e.isTrigger != undefined) {
            console.log(val);
        }
    }
    

    That means you must add the event parameter to the inline function:

    onchange="sendItem(this.value, event)"
    

    The snippet:

    function sendItem(ele, e) {
        if (e.isTrigger != undefined) {
            console.log(ele.value + '   url if any: ' + $(ele).nextAll('.dropdown-content').find('img').attr('src'));
        }
    }
    
    $(function () {
        $('input.autocomplete').autocomplete({
            data: {
                "Apple": null,
                "Microsoft": null,
                "Google": 'http://placehold.it/250x250'
            },
            limit: 20, // The max amount of results that can be shown at once. Default: Infinity.
        });
    });
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/js/materialize.min.js"></script>
    
    
    <div class="row">
        <div class="col s12">
            <div class="row">
                <div class="input-field col s12">
                    <input type="text" id="autocomplete-input" class="autocomplete" onchange="sendItem(this, event)">
                    <label for="autocomplete-input">Autocomplete</label>
                </div>
            </div>
        </div>
    </div>