Search code examples
ruby-on-railsmaterialize

How to apply a CSS class to a Select using Materialize and SimpleForm in Rail 5


I'm having a bit of trouble getting a class to stick in the right spot using SimpleForm and Materialize with Select inputs.

The Materialize simpleform wrappers from this gem (https://github.com/jamesfwz/materialize-form) work great for most fields but if I want a field to load with the Invalid class for a Select field, I cant get it right.

Heres a working example say with a text field. In my view:

<%= f.input :suburb,  input_html: {class: "invalid"} %>

Output:

<div class="input-field col string optional">
  <input class="string optional invalid" type="text" ....>Suburb</label></div>

Which correctly appears with its invalid formatting.

When I try it with a select input, I can't get the class in the right spot. Ie. the associated Materialize text input it creates using js.

Using wrapper_html option in my view:

<%= f.input :state,              
        collection: ["VIC","NSW","TAS","SA","ACT","WA"], 
        wrapper_html: { class: 'invalid' }

Which puts the class on the outer wrapper, but not the visible text element:

<div class="input-field col select optional invalid">
  <div class="select-wrapper">
    <input class="select-dropdown dropdown-trigger" type="text" readonly="true">
      <ul id="select-..." class="dropdown-content select-dropdown" tabindex="0">
        <li id="select-options-..." tabindex="0" class="selected"><span>

Which doesn't show correctly.

I've tried the input_html option;

<%= f.input :state,              
        collection: ["VIC","NSW","TAS","SA","ACT","WA"], 
        input_html: { class: 'invalid' }

Which puts the class on the Select element, but not the visible text element

<div class="input-field col select optional ">
  <div class="select-wrapper">
    <input class="select-dropdown dropdown-trigger" type="text" readonly="true">
       <ul id="select-options-..." class="dropdown-content select-dropdown" tabindex="0">
         <li ...</li></ul>
           <select class="select optional invalid" name="...">
             <option value=""></option>

I've tried the straight class option;

<%= f.input :state,              
        collection: ["VIC","NSW","TAS","SA","ACT","WA"], 
        class: 'invalid'

Which doesn't have the class appear anywhere (unsurprisingly)

Lastly, I've tried the html_options option hoping it would get passed to the collection_select method and get picked up by Materialize

<%= f.input :state,              
        collection: ["VIC","NSW","TAS","SA","ACT","WA"], 
        class: 'invalid'

Which doesn't have the class appear anywhere (even more unsurprisingly!)

What am I getting wrong?


Solution

  • you can use option_for_select

    invalid_value = "NSW"
    values = ["VIC","NSW","TAS","SA","ACT","WA"].map { |v| v == invalid_value ? [v, class: 'invalid'] : v  }
    => ["VIC", ["NSW", {:class=>"invalid"}], "TAS", "SA", "ACT", "WA"]
    

    then

    <%= f.select :state, options_for_select(values, invalid_value), include_blank: true %>
    

    Edit:

    To add class to Materialize generated select

    <%= form.input :state, collection:  ["VIC","NSW","TAS","SA","ACT","WA"], input_html: { class: "invalid" } %>
    

    Add add some JS
    This should run after Materialize drop down is generated

    $('select.invalid').each(function(){
      $(this).parent().addClass('invalid')
    })