jQuery selectmenu onchange

1.5k views Asked by At

I want to make a select menu with icons and the text you select should be shown in a text on top (or the icon). My problem is that the on change method is not working.

What's going wrong?

$(function() {
  $.widget("custom.iconselectmenu", $.ui.selectmenu, {
    _renderItem: function(ul, item) {
      var li = $("<li>"),
        wrapper = $("<div>", {
          text: item.label
        });

      if (item.disabled) {
        li.addClass("ui-state-disabled");
      }

      $("<span>", {
        style: item.element.attr("data-style"),
        "class": "ui-icon " + item.element.attr("data-class")
      }).appendTo(wrapper);

      return li.append(wrapper).appendTo(ul);
    },
    select: function(event, ui) {
      console.log("test")
    }
  });

  $("#icons_id")
    .iconselectmenu()
    .iconselectmenu("menuWidget")
    .addClass("ui-menu-icons avatar");

});

var select = document.getElementById("icons_id");

var options = ["Aufgabe", "Gruppe", "Schritt", "Werkzeug", "Dokument"];

for (var i = 0; i < options.length; i++) {

  var opt = options[i];

  var el = document.createElement("option");

  var icon = opt;

  el.style

  el.textContent = opt;

  el.value = opt;


  select.appendChild(el);

}

function myFunction() {

  var x = document.getElementById("icons_id").value;

  document.getElementById("demo_text").innerHTML = "You selected: " + x;

}
option.avatar {
  background-repeat: no-repeat !important;
  padding-left: 20px;
}

.avatar .ui-icon {
  background-position: left top;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link href="https://code.jquery.com/ui/1.12.0/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script>


<h2 id="test">Dropdown Menu</h2>

<p id="demo_text">You selected: </p>

<select name="icons_name" id="icons_id" onchange="myFunction()">

  <option data-class="avatar" data-style="background-image: url(&apos;http://www.gravatar.com/avatar/b3e04a46e85ad3e165d66f5d927eb609?d=monsterid&amp;r=g&amp;s=16&apos;);">1</option>

  <option data-class="avatar" data-style="background-image: url(&apos;http://www.gravatar.com/avatar/e42b1e5c7cfd2be0933e696e292a4d5f?d=monsterid&amp;r=g&amp;s=16&apos;);">2</option>

  <option data-class="avatar" data-style="background-image: url(&apos;http://www.gravatar.com/avatar/bdeaec11dd663f26fa58ced0eb7facc8?d=monsterid&amp;r=g&amp;s=16&apos;);">3</option>

</select>

3

There are 3 answers

0
Tom Maher On

I think the problem that you're having is that you are adding a select method to your widget not setting a select method on the base widget (selectmenu) to use as an event handler.

The following should work:

$(function() {
  $.widget("custom.iconselectmenu", $.ui.selectmenu, {
    _create: function(){
        this.element.on("selectmenuselect", function( event, ui ) {
            console.log("test");
        } ););
    }

    _renderItem: function(ul, item) {
      var li = $("<li>"),
        wrapper = $("<div>", {
          text: item.label
        });

      if (item.disabled) {
        li.addClass("ui-state-disabled");
      }

      $("<span>", {
        style: item.element.attr("data-style"),
        "class": "ui-icon " + item.element.attr("data-class")
      }).appendTo(wrapper);

      return li.append(wrapper).appendTo(ul);
    }
  });
12
showdev On

The change event of the original <select> element won't fire, since you're manipulating elements of the Selectmenu widget and not the <select>. You could manually trigger the change on the original element, e.g. .trigger("change"), but you might instead consider using the Selectmenu widget's change event to fire your function.

In the snippet below, I've moved the change event out of the widget customization and into the iconselectmenu initialization.

Like this:

.iconselectmenu({
  change: myFunction
})

(Also see Tom Maher's answer for a different way to define the select event handler.)

Working example:

$(function() {
  $.widget("custom.iconselectmenu", $.ui.selectmenu, {
    _renderItem: function(ul, item) {
      var li = $("<li>"),
        wrapper = $("<div>", {
          text: item.label
        });

      if (item.disabled) {
        li.addClass("ui-state-disabled");
      }

      $("<span>", {
        style: item.element.attr("data-style"),
        "class": "ui-icon " + item.element.attr("data-class")
      }).appendTo(wrapper);

      return li.append(wrapper).appendTo(ul);
    }
  });

  $("#icons_id")
    .iconselectmenu({
      change: myFunction
    })
    .iconselectmenu("menuWidget")
    .addClass("ui-menu-icons avatar");

});


var select = document.getElementById("icons_id");
var options = ["Aufgabe", "Gruppe", "Schritt", "Werkzeug", "Dokument"];

for (var i = 0; i < options.length; i++) {
  var opt = options[i];
  var el = document.createElement("option");
  var icon = opt;
  el.textContent = opt;
  el.value = opt;
  select.appendChild(el);
}

function myFunction() {
  var x = document.getElementById("icons_id").value;
  document.getElementById("demo_text").innerHTML = "You selected: " + x;
}
option.avatar {
  background-repeat: no-repeat !important;
  padding-left: 20px;
}

.avatar .ui-icon {
  background-position: left top;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link href="https://code.jquery.com/ui/1.12.0/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script>


<h2 id="test">Dropdown Menu</h2>
<p id="demo_text">You selected: </p>

<select name="icons_name" id="icons_id" onchange="myFunction()">
  <option data-class="avatar" data-style="background-image: url(&apos;http://www.gravatar.com/avatar/b3e04a46e85ad3e165d66f5d927eb609?d=monsterid&amp;r=g&amp;s=16&apos;);">1</option>
  <option data-class="avatar" data-style="background-image: url(&apos;http://www.gravatar.com/avatar/e42b1e5c7cfd2be0933e696e292a4d5f?d=monsterid&amp;r=g&amp;s=16&apos;);">2</option>
  <option data-class="avatar" data-style="background-image: url(&apos;http://www.gravatar.com/avatar/bdeaec11dd663f26fa58ced0eb7facc8?d=monsterid&amp;r=g&amp;s=16&apos;);">3</option>
</select>


Edit:

One way to add the icon to #demo_text is to reference the same data-style attribute you use when rendering the widget. Within the change event handler, I'm grabbing the background image and creating an icon element to append to #demo_text along with the selected option's value.

Also, since you're using jQuery, I chose to write the code in jQuery rather than vanilla JavaScript.

$(function() {
  $.widget("custom.iconselectmenu", $.ui.selectmenu, {
    _renderItem: function(ul, item) {

      var li = $("<li>");

      var wrapper = $("<div>", {
        "text": item.label,
      });

      if (item.disabled) {
        li.addClass("ui-state-disabled");
      }

      $("<span>", {
        "style": item.element.attr("data-style"),
        "class": "ui-icon " + item.element.attr("data-class")
      }).appendTo(wrapper);

      return li.append(wrapper).appendTo(ul);

    }
  });

  $("#icons_id")
    .iconselectmenu({
      change: myFunction
    })
    .iconselectmenu("menuWidget")
    .addClass("ui-menu-icons avatar");

});


var options = ["Aufgabe", "Gruppe", "Schritt", "Werkzeug", "Dokument"];
var $select = $('#icons_id');
var $display = $('#demo_text');

$.each(options, function() {
  var $option = $('<option>', {
    "value": this,
    "text": this
  });
  $select.append($option);
});

function myFunction(e, ui) {
  var $value = $("<span>", {
    "text": $select.val()
  });
  var $icon = $("<span>", {
    "style": ui.item.element.data("style"),
    "class": "ui-icon "
  });
  $display.text('You selected: ').append($icon, $value);
}
option.avatar {
  background-repeat: no-repeat !important;
  padding-left: 20px;
}

.avatar .ui-icon {
  background-position: left top;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link href="https://code.jquery.com/ui/1.12.0/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script>


<h2 id="test">Dropdown Menu</h2>
<p id="demo_text">You selected: </p>

<select name="icons_name" id="icons_id" onchange="myFunction()">
  <option data-class="avatar" data-style="background-image: url(&apos;http://www.gravatar.com/avatar/b3e04a46e85ad3e165d66f5d927eb609?d=monsterid&amp;r=g&amp;s=16&apos;);">1</option>
  <option data-class="avatar" data-style="background-image: url(&apos;http://www.gravatar.com/avatar/e42b1e5c7cfd2be0933e696e292a4d5f?d=monsterid&amp;r=g&amp;s=16&apos;);">2</option>
  <option data-class="avatar" data-style="background-image: url(&apos;http://www.gravatar.com/avatar/bdeaec11dd663f26fa58ced0eb7facc8?d=monsterid&amp;r=g&amp;s=16&apos;);">3</option>
</select>


Edit:

Here's an example of how to populate the <select> element purely from an array of objects, so that you can specify an icon for each <option>.

I also used code from this post to show a "placeholder" for the dropdown prior to user selection.

I also switched from the change event to the select event. The first option is selected by default (even though the placeholder is showing), so change doesn't fire if you select it again.

$(function() {

  /* Customize Widget */

  $.widget("custom.iconselectmenu", $.ui.selectmenu, {
    _drawButton: function() {
      this._super();
      var selected = this.element
        .find('[selected]')
        .length,
        placeholder = this.options.placeholder;

      if (!selected && placeholder) {
        this.buttonItem.text(placeholder);
      }
    },
    _renderItem: function(ul, item) {

      var style = "background-image:url('" + item.element.attr("data-icon") + "')";

      var li = $("<li>");

      var wrapper = $("<div>", {
        "text": item.label,
      });

      if (item.disabled) {
        li.addClass("ui-state-disabled");
      }

      $("<span>", {
        "style": style,
        "class": "ui-icon"
      }).appendTo(wrapper);

      return li.append(wrapper).appendTo(ul);

    }
  });

  /* Define Select Handler */

  function chooseOption(e, ui) {
    var style = "background-image:url('" + options[ui.item.index]['data-icon'] + "')";
    var $value = $("<span>", {
      "text": $select.val()
    });
    var $icon = $("<span>", {
      "style": style,
      "class": "ui-icon"
    });
    $display.text('You selected:').append($icon, $value);
  }

  /* Define Select Options */

  var options = [{
      'value': 'Aufgabe',
      'text': 'Aufgabe',
      'data-icon': 'http://www.gravatar.com/avatar/b3e04a46e85ad3e165d66f5d927eb609?d=monsterid&r=g&s=16'
    },
    {
      'value': 'Gruppe',
      'text': 'Gruppe',
      'data-icon': 'http://www.gravatar.com/avatar/e42b1e5c7cfd2be0933e696e292a4d5f?d=monsterid&r=g&s=16'
    },
    {
      'value': 'Schritt',
      'text': 'Schritt',
      'data-icon': 'http://www.gravatar.com/avatar/bdeaec11dd663f26fa58ced0eb7facc8?d=monsterid&r=g&s=16'
    },
    {
      'value': 'Werkzeug',
      'text': 'Werkzeug',
      'data-icon': 'https://picsum.photos/30/30/?image=2'
    },
    {
      'value': 'Dokument',
      'text': 'Dokument',
      'data-icon': 'https://picsum.photos/30/30/?image=12'
    }
  ];

  /* Generate Select Options */

  var $select = $('#icons_id');
  var $display = $('#demo_text');

  $.each(options, function() {
    var $option = $('<option>', this);
    $select.append($option);
  });

  /* Initialize SelectMenu */

  $("#icons_id")
    .iconselectmenu({
      placeholder: 'Select an Option',
      select: chooseOption
    })
    .iconselectmenu("menuWidget")
    .addClass("ui-menu-icons");

});
.ui-icon {
  background-position: left center;
}

#demo_text .ui-icon {
  margin: 0 .5em;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link href="https://code.jquery.com/ui/1.12.0/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script>

<p id="demo_text"></p>
<select name="icons_name" id="icons_id"></select>

5
Ryuk Lee On

You miss the value for options

    function myFunction() {
      var x = document.getElementById("icons_id").value;    
      document.getElementById("demo_text").innerHTML = "You selected: " + x;    
    }
    <h2 id="test">Dropdown Menu</h2>

    <p id="demo_text">You selected: </p>

    <select name="icons_name" id="icons_id" onchange="myFunction()">

      <option value="1" data-class="avatar" data-style="background-image: url(&apos;http://www.gravatar.com/avatar/b3e04a46e85ad3e165d66f5d927eb609?d=monsterid&amp;r=g&amp;s=16&apos;);">1</option>

      <option value="2" data-class="avatar" data-style="background-image: url(&apos;http://www.gravatar.com/avatar/e42b1e5c7cfd2be0933e696e292a4d5f?d=monsterid&amp;r=g&amp;s=16&apos;);">2</option>

      <option value="3" data-class="avatar" data-style="background-image: url(&apos;http://www.gravatar.com/avatar/bdeaec11dd663f26fa58ced0eb7facc8?d=monsterid&amp;r=g&amp;s=16&apos;);">3</option>

    </select>