fearless_fool
fearless_fool

Reputation: 35149

How to trigger a selection using onchange using unobtrusive jQuery

Assume I have a vanilla form containing a selection list and a submit button:

<%= form_for(@report :url => report_path) do |f| %>
  <%= f.select(:sort_by, options_for_select(Report.SORT_OPTIONS, @report.sort_by)) %>
  <%= f.submit 'sort' %>
<% end %>

Works fine, except that the user has to first make a selection and then click 'sort'. What I'd really like is to have the action triggered when the user makes a selection and to ditch the 'sort' button altogether. This feels like a perfect use case for unobtrusive jQuery.

So [based on responses from @Dennis and @ethan below], before this form_for I added:

<%= javascript_include_tag(:defaults) %>

<script type="text/javascript">
$(document).ready(function() { 
  var $select = $('#report_sort_by'),
      $form = $select.closest('form');
  // $('[type="submit"]', $form).attr('type', 'hidden'); // gives error
  $('[type="submit"]', $form).hide();                    // works
  $select.change(function() { $form.submit(); });
});
</script>  

So is it considered right to plunk javascript right into the .html.erb file? Or is it better to put this in a separate .js file, and if so, what are the conventions for paramaterizing and naming the .js file?

For a few reputation points, can someone show me and all the other tyros how to do this?

Upvotes: 0

Views: 1433

Answers (2)

ethan
ethan

Reputation: 156

Rails will stringify the object & property you're using, so the select menu would have id="report_sort_by". Which means you could use:

var $select = $('#report_sort_by'),
    $form = $select.closest('form');

// preserve the button's name/value attributes, if Rails has assigned them
$('[type="submit"]', $form).hide();

$select.change(function() {
  $form.submit();
});

If you want to include this code in a robust, unobtrusive way, you could make a file called maybe MyProject.Report.js and put this code in it:

if (!MyProject) var MyProject = {};

MyProject.Report = {
  init: function() {
    var $select = $('#report_sort_by'),
        $form = $select.closest('form');

    // preserve the button's name/value attributes, if Rails has assigned them
    $('[type="submit"]', $form).hide();

    $select.change(function() {
      $form.submit();
    });
  }
}

Then in your .erb file (at the bottom, after the form) you could add <script type="text/javascript">MyProject.Report.init();</script> and then, of course, add the javascript_include_tag to include the JS file itself.

There's a bunch of different ways you could do your namespacing & encapsulation. The MyProject.Report object that I describe above has the chief advantage of being incredibly straightforward. As your code grows, you just add new functionality inside the MyProject.Report object like:

MyProject.Report = {
  init: function(options) {
    // some event handlers, maybe
    this.complication(null, null, options.data);
    this.reusable(options.bgcolor);
  },

  complication: function(a, b, c) {
    // stuff that's tough to look at
    this.reusable(b);
  },

  reusable: function(q) {
    // code that's used multiple places
  }
}

And then you basically hack away at that until you're knowledgeable enough to decide whether you need a framework like backbone.js for a given project :)

Upvotes: 2

Dennis
Dennis

Reputation: 32598

I'm not familiar with Ruby-on-Rails, so you may have to change the selectors but the general idea is:

$("#formId input[type='submit']").hide(); //Make the submit button invisible

$("#formId select.selectClass").change( function() {
    $(this).closest("form").submit(); //Trigger the submit event on the parent form.
});


It looks like you can set the id like this:

:html => {:id => 'formId', :method => :put }

Upvotes: 1

Related Questions