Saturday, July 8, 2017

How do you get the Ruby on Rails generated id of a form element for reference in JavaScript?

Leave a Comment

When using the form_for helper and a text_field call, Ruby on Rails will generate a unique id for the <input /> element that it outputs. How can I generate the same id for later inclusion into JavaScript generated later?

<%= form_for @user do |f| %>   <%= f.text_field :username %> <% end %> 

Then later in the page:

<%= javascript_tag do %>   $('<%= id of the :username field %>').doSomethingReallyCool(); <% end %> 

7 Answers

Answers 1

I ended up creating a custom form builder to expose the property directly

class FormBuilder < ActionView::Helpers::FormBuilder   def id_for(method, options={})    InstanceTag.new( object_name, method, self, object ) \                .id_for( options )                  end end  class InstanceTag < ActionView::Helpers::InstanceTag   def id_for( options )     add_default_name_and_id(options)     options['id']   end end 

Then set the default form builder

ActionView::Base.default_form_builder = FormBuilder  

Answers 2

Look at the form builder options:

<%= form_for @user do |f| %>   <% form_css_id = "#" + f.options[:html][:id] %> <% end %> 

Options should at least include the following data: css class, id, http method and authenticity token.

Answers 3

You'll want to specify the id yourself

<%= form_for @user do |f| %>   <%= f.text_field :username, :id=>"supercool_username" %> <% end %>  <%= javascript_tag do %>   $('#supercool_username').doSomethingReallyCool(); <% end %> 

Answers 4

In case someone has a FormBuilder object from a fields_for block, get its id using this snippet:

<%= form.fields_for :something do |fields_form| %>   <%= fields_form.object_name.gsub(/[/[/]]+/, '_').chop %>id <% end %> 

FieldsForm#object_name returns the field's ID as something like this: user[address][0]. Next, the regex substitution changes groups of one or more brackets to underscores. This substitution leaves a trailing underscore, to which it appends the letters id. For the example provided before, this results in user_address_0_id.

Answers 5

I don't really like my own solution that much, but I tried not to go and patch InstanceTag.

Unfortunately that meant lifting the sanitization code from ActionView::Helpers::InstanceTagMethods

class MyCoolFormBuilder < ActionView::Helpers::FormBuilder     def sanitized_object_name       @sanitized_object_name ||= object_name.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")     end      def field_id_for(method)       "#{sanitized_object_name}_#{method.to_s.sub(/\?$/,"")}"     end end 

Answers 6

Since your Javascript code is placed in a ruby embedded file (.erb) that is being interpreted by the server before being sent to the client browser, you can generated the required JS variable with a ruby snippet like:

var id='#id_for_'+<%= @user.username %> var id='#comment_info_'+<%= n %> 

and then use it simply as $(id).doSomethingReallyCool();.

If you need to control the value of the id generated by the form in first instance, you can do it passing the id in the html hash options:

f.text_field :username, id:"id_for_#{…}" 

If you're using a unobtrusive JS approach, you would like to place the JS code into a partial (.js.erb) and have the controller use it if the user client allows JS. E.g.:

class FooController < ApplicationController  def foo_doo   … # some logic   respond_to do |format|     format.js # this will render javascript in file “foo_doo.js.erb” if allowed     format.html { … } # html fallback for unobtrusive javascript   end end 

This is the recommended approach nowadays. The problem now is that you need to pass the variables to your JS code. If these variables came from a form, place them in opportune hidden form fields. And then use the render's locals option to have them available by your partial, as in:

format.js { render 'foo_doo', locals: {n:n} } 

If the JS code is updating a template that use some variables, use the same approach:

var id='#comment_info_'+<%= n %> $(id).replaceWith("<%= j (render partial:…, locals: {…}) %>") 

Answers 7

I assume that there are multiple form_for in the page and each has it's own submit button. I think this is how I would do this:

Have a hidden field in the the form_for and set it's value to the id of the input field. Here I've chosen input_#{n} as the id of the input field. Of course I'll define the id for each input.

<%= form_for @user do |f| %>   <%= f.text_field :username, id: "input_#{n}" %>   <%= hidden_field_tag 'user[input_id]', value: "input_#{n}" %>   <%= f.submit %> <% end %>    

Then on submit I can get the id the form input in my params params[:user][:input_id] which I can pass to the js.erb using the locals.

Hope this helps :)

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment