Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
client_side_validations with select2 and Ajax

Possible complete Select2 integration

Full live (client side) validation, "developed" to use with simple_form and foundation markup (should work in other cases too).

Create separate .coffee file e.g. client_side_select2.js.coffee with following code:

# Add select2 support
ClientSideValidations.selectors.validate_inputs += ', select[data-select2-validate]'
ClientSideValidations.selectors.inputs += ', .select2-container'

getSelect2 = (element) ->
  $(element).parent().find('select')

$.fn.base = window.ClientSideValidations.enablers.input

window.ClientSideValidations.enablers.input = (element) ->
  extend = ->
    unless $(element).hasClass 'select2-container'
      $.fn.base(element)
    else
      $placeholder = $(element)
      $select = $placeholder.parent().find('select')
      form   = $select[0].form
      $form  = $(form)

      if $select.attr('data-select2-validate')
        # only focus event should be handled by placeholder
        $placeholder.on(event, binding) for event, binding of {
          'focusout.ClientSideValidations': ->
            getSelect2(@).isValid(form.ClientSideValidations.settings.validators)
        }
        $select.on(event, binding) for event, binding of {
          'change.ClientSideValidations':   -> getSelect2(@).data('changed', true)
          # Callbacks
          'element:validate:after.ClientSideValidations':  (eventData) -> ClientSideValidations.callbacks.element.after(getSelect2(@),  eventData)
          'element:validate:before.ClientSideValidations': (eventData) -> ClientSideValidations.callbacks.element.before(getSelect2(@), eventData)
          'element:validate:fail.ClientSideValidations':   (eventData, message) ->
            element = $(@)
            ClientSideValidations.callbacks.element.fail(element, message, ->
              form.ClientSideValidations.addError(element, message)
            , eventData)
          'element:validate:pass.ClientSideValidations':   (eventData) ->
            element = $(@)
            ClientSideValidations.callbacks.element.pass(element, ->
              form.ClientSideValidations.removeError(element)
            , eventData)
        }
  extend()

Require this file after rails.validations in your appplication.js.coffee e.g.:

#= require rails.validations
#= require client_side_select2

Now add data-select2-validate="true" attribute to your select2 select element to get the following markup:

<select data-select2-select="true" data-select2-validate="true" style="display: none;">
  <option value="">Default option</option>
  <option value="1">Option 1</option>
  ... other options ...
</select>

<span class="select2 select2-container select2-container--default" dir="ltr" style="width: 291px;">
  ... rest of the select2 markup ...
</span>

Now everything should work.

Good luck.

I suppose that support for select2 without validation might be an issue with the code above, but I'm not sure.

It could cause issues when used with Turbolinks.

Ajax support

For AJAX support (including turbolinks) you should execute following code to reinitialize validations.

# initialize select2
$select2 = $wrapper.find('[data-select2-select]').select2()
# initialize client_side_validations
$select2.parent().find('.select2-container').enableClientSideValidations()

Of course this should be executed on Ajax success response, only for new elements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment