jQuery selectmenu onchange

Я хочу сделать меню выбора со значками, а выбранный вами текст должен отображаться в тексте сверху (или значке). Моя проблема в том, что метод on change не работает.

Что происходит не так?

$(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>


person Jvliqn_    schedule 27.02.2019    source источник
comment
Вандализм в собственном вопросе - это уже достаточно плохо, но это оскорбление, когда вы пытаетесь испортить ответы других, пытаясь удалить из них код.   -  person Adriaan    schedule 27.02.2019


Ответы (3)


Событие change исходного элемента <select> не сработает, так как вы манипулируете элементами виджета Selectmenu, а не <select>. Вы можете вручную активировать change для исходного элемента, например. .trigger("change"), но вместо этого вы можете использовать событие change виджета Selectmenu для запуска вашей функции. .

В приведенном ниже фрагменте я переместил событие change из настройки виджета в инициализацию iconselectmenu.

Как это:

.iconselectmenu({
  change: myFunction
})

(Также см. ответ Тома Махера, чтобы узнать о другом способе определения обработчика событий select.)

Рабочий пример:

$(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>


Редактировать:

Один из способов добавить значок в #demo_text — это указать тот же атрибут data-style, который вы используете при рендеринге виджета. В обработчике событий change я беру фоновое изображение и создаю элемент значка для добавления к #demo_text вместе со значением выбранного параметра.

Кроме того, поскольку вы используете jQuery, я решил написать код на jQuery, а не на ванильном 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>


Редактировать:

Вот пример того, как заполнить элемент <select> исключительно из массива объектов, чтобы вы могли указать значок для каждого <option>.

Я также использовал код из этот пост, чтобы показать "заполнитель" для раскрывающийся список перед выбором пользователя.

Я также переключился с события change на событие select. Первый вариант выбран по умолчанию (даже несмотря на то, что заполнитель отображается), поэтому change не сработает, если вы выберете его снова.

$(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>

person showdev    schedule 27.02.2019
comment
спасибо все работает.. теперь проблема в том, что иконка не отображается в тексте - person Jvliqn_; 27.02.2019
comment
Это отдельная тема. Вам нужно будет добавить элемент значка в #demo_text таким же образом, как вы добавляете его в часть _render виджета. - person showdev; 27.02.2019
comment
как бы вы сделали это именно? Я понятия не имею - person Jvliqn_; 27.02.2019
comment
Я отредактировал свой ответ, включив в него один способ добавления значка. - person showdev; 27.02.2019
comment
а еще ты знаешь как я это делаю что у меня еще есть массив строк (или такой же) который задает пути к иконкам, которые потом отображаются в опции и в тексте? - person Jvliqn_; 27.02.2019
comment
потому что на данный момент сгенерированные варианты из массива имеют просто стрелку в качестве значка - person Jvliqn_; 27.02.2019
comment
Я снова отредактировал, чтобы продемонстрировать способ указать значок каждой опции. Однако это выходит за рамки вашего первоначального вопроса. Вы можете опубликовать другой вопрос для других возникающих проблем. Просто дружеское предложение. - person showdev; 27.02.2019
comment
Хорошо, теперь это работает, спасибо: D. Другое дело: Как там с размером иконки. На данный момент работают только иконки размером 16px. Можно ли использовать иконки размером 32px? - person Jvliqn_; 27.02.2019
comment
Конечно, но вам нужно настроить CSS для обработки больших значков. Класс .ui-icon в пользовательском интерфейсе jQuery установлен на 16px X 16px. - person showdev; 27.02.2019
comment
да, я понял :D А ты знаешь, как сделать опцию в опции? - person Jvliqn_; 27.02.2019
comment
@showdev Я проголосовал за ваш ответ, так как он является наиболее полным из всех полученных ответов, и я не знаю, почему оператор не отметил ваш ответ как правильное решение. - person Tom Maher; 27.02.2019
comment
да, я понял :D А ты знаешь, как сделать опцию в опции? - person Jvliqn_; 27.02.2019

Я думаю, что проблема, с которой вы столкнулись, заключается в том, что вы добавляете метод выбора в свой виджет, не устанавливая метод выбора в базовом виджете (selectmenu) для использования в качестве обработчика событий.

Следующее должно работать:

$(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);
    }
  });
person Tom Maher    schedule 27.02.2019

Вы упускаете значение опций

    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>

person Ryuk Lee    schedule 27.02.2019
comment
Не уверен, почему это было принято, но это вообще не относится к виджету selectmenu. Кроме того, если <option> не имеет атрибута value, будет использоваться его текст. - person showdev; 27.02.2019
comment
Да, но это самый простой способ решить этот случай. Спасибо - person Ryuk Lee; 27.02.2019
comment
Решить какое дело? OP не имеет проблем с получением value. - person showdev; 27.02.2019
comment
Как вы думаете, чем отличаются value и text? Что плохого в том, что они ведут стандартный html? - person Ryuk Lee; 27.02.2019
comment
Я имею в виду без обид. В вашем предложении нет ничего плохого, но оно может быть лучше в качестве комментария. Элементы допустимы без атрибута value, значение и текст OP не отличаются, и включение атрибута value, на мой взгляд, не решает представленную проблему. - person showdev; 27.02.2019