Search code examples
ruby-on-railsruby-on-rails-3dom-eventsonchange

How to add an onchange listener for form elements in Ruby on Rails?


I am writing a form in Ruby on Rails and want to have a select box that calls a Javascript function. In the form file, this is the line I am using to try to add the select box:

<%= f.select :question_select, Question.all, :prompt => "New Question", :onchange => "displayQuestion(this)" %>

In my application.js file, I just have:

function displayQuestion(link) {
    alert("Changed question");
}

I am going to be dynamically adding these form elements to a page, so I can't just use jQuery in the application.js file to add a function to a specific form element. Can anyone tell me what I'm doing wrong?


Solution

  • As you may know, Rails 3 strongly encourages UJS (unobtrusive JavaScript), which basically means that the JavaScript does the heavy lifting, and that you shouldn't tie your client-side interactivity in with your form generators. I would recommend doing something very similar here--just because you're adding elements dynamically doesn't mean you can't use jQuery to watch for changes on them.

    In your template:

    <%= f.select :question_select, Question.all, {prompt: "New Question"}, data: { question: true } %>
    

    This creates something like the following:

    <select id="..." data-question="true">
      ...
    </select>
    

    Then, in JavaScript, you can use event delegation to watch for change events on any element with data-question set on the entire document:

    $(function() {
      $(document).on('change', '[data-question]', function() {
        // this == the element that fired the change event
        alert('Changed question');
      });
    });
    

    Note: Instead of using data-question, you could simply add a class to the element, and then modify your jQuery to use that class:

    $(function() {
      $(document).on('change', '.question', function() {
        // this == the element that fired the change event
        alert('Changed question');
      });
    });
    

    I generally try to minimize the use of CSS selectors in my JavaScript so that designers are free to change them to whatever they want without breaking things, but it works just as well.