Search code examples
jquerysemantic-ui

Add custom data attributes to Semantic UI Dropdown when items are retrieved via Ajax


Here is how I was building my dropdown (in haml):

#my_dropdown.ui.dropdown{ data: { path: objects_path } }
  = f.hidden_field :my_id
  %i.dropdown.icon
  .default.text Text
  .menu
    - @collection.each do |object|
      .item{ data: { value: object.id, text: object.name, color: object.color } }
        = object.name

This was working great. My .item elements had extra data, such as .data('color'). I decided I wanted to switch to an ajax approach instead of loading all of the elements at once.

$.fn.api.settings.api =
    'search objects': $('#my_dropdown').data('path') + '?q={query}'

$('#my_dropdown').dropdown
    apiSettings:
      action: 'search objects'

    onChange: (value, text, selectedItem) ->
      console.log selectedItem.data()

Here is what my returned JSON looks like:

{
  "success":true,
  "results": [
    { "name":"Object #1", "value":1, "color":"blue" },
    { "name":"Object #2", "value":2, "color":"red" },
    { "name":"Object #3", "value":3, "color":"green" }
  ]
}

When I do the console.log selectedItem.data() after the dropdown select is changed, I only see:

{ value: 1 }

And the generated HTML looks like:

<div class="item" data-value="1">Object #1</div>
<div class="item" data-value="2">Object #2</div>
<div class="item" data-value="3">Object #3</div>

How can I get the items to include the custom data attributes, such as data-color while using Ajax?


Solution

  • I was able to manually override the Semantic UI menu template with the following code:

    $.fn.dropdown.settings.templates =
      menu: (response, fields) ->
        values = response[fields.values] or {}
        html = ''
        $.each values, (index, option) ->
          extraData = ''
          $.each fields.extraAttrs, (_j, attr) ->
            if option[attr]
              extraData += "data-#{attr}='" + option[attr] + "''"
    
          maybeText = if option[fields.text] then 'data-text="' + option[fields.text] + '"' else ''
          maybeDisabled = if option[fields.disabled] then 'disabled ' else ''
          html += '<div class="' + maybeDisabled + 'item" data-value="' + option[fields.value] + '"' + extraData + maybeText + '>'
          html += option[fields.name]
          html += '</div>'
          return
        html
    

    Then when I'm initializing my dropdown, I can do:

    $('#my_dropdown').dropdown
        apiSettings:
          action: 'search objects'
        fields:
          extraAttrs: ['color']
    

    That allows me to access extra data elements on each of the dropdown items. If someone has a better way to do this, please let me know.