Search code examples
javascriptjquery-select2

How do you create a drop-menu with images next to each option in JS?


I looked up several tutorials on how to get the image next to the title, however, they are for small datasets that are manually inputted. Having almost 3,000 rows of data, there has to be a better way.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0" SameSite=None; Secure>
  <title>Document</title>

  <script
    type="text/javascript"
    src="https://d3js.org/d3.v3.js"
  ></script>
  <style id="compiled-css" type="text/css">
  
  </style>
</head>
<body>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.8/js/select2.min.js" defer></script>
  <script src="http://d3js.org/d3.v3.js"></script>
  <script src="static/js/app.js"></script>
  <script></script>
</body>
</html>

I edited the code and data. I am not receiving any errors in the vs code console, nor the http console. Yet, the text appears in the drop-menu, but not the images.

d3.csv("https://raw.githubusercontent.com/Shannon-Goddard/grow_data/main/Resources/csv/ALL_data.csv", function(error, data) {
    var select = d3.select("body")
      .append("div")
      .append("select")

    select
      .on("change", function(d) {
        $("#idselector").select2();
        var value = d3.select(this).property("value");
        alert(value);
      });

      select.selectAll("option")
      .data(data)
      .enter()
        .append("option")
        .text(function (d) { return d.strain; })
        .append(function(d) {
          const logo = document.createElement('img');
          logo.src = d.logo;
          return logo;
      });

});


There are no errors in my vs code console, nor the http console...


Solution

  • Your images are there, JavaScript just doesn't support displaying them natively and Select2 appears to be misconfigured. If you inspect element on your <option> elements, you'll see your images there, but Select2 doesn't know to render them. Examples of rendering images using Select2 tend to stash the image data into a "data" attribute and retrieving them with a customer templateSelection and templateResult renderer.

    Although if you remove Select2 as a dependency, the question is really a duplicate of How to add images in select list? however the question is quite old and many of the answers are outdated.

    Since your other questions referenced jQuery, I would recommend trying jQuery's SelectMenu with a custom renderer.

    https://jqueryui.com/selectmenu/#custom_render

    Take special attention to the data-style example with "Select a Person" (e.g. "John Resig") as it uses a bit of style-injection so that you can dynamically add all of the images into your HTML as a form of style tag.

    style: item.element.attr( "data-style" )
    

    Which is pulled from data-style="..." however take special note of special HTML escaping that's mandatory when injecting styles like this, such as &apos;, etc.

    <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;);">John Resig</option>
     
    

    To simplify this a bit and avoid some of the ugly HTML escaping, I recommend you just store the image URL in the data attribute (e.g. rename to data-image) and construct the style tag manually from JavaScript, e.g. style: "background-image: url('" + item.element.attr( "data-image" ) + "');"

    It will take a bit of work to get the image size and styling right for the drop-down, but it's exactly what the jQuery SelectMenu's custom renderer was intended for. If you find the render to not suit your needs, some non-jQuery alternatives are proposed here.