Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #3231 (closed defect: wontfix)

Opened 4 years ago

Last modified 3 years ago

multiple submit buttons in form_remote_tag won't work with params[:commit] as in form_tag

Reported by: anonymous Assigned to: David
Priority: high Milestone: 1.x
Component: ActionPack Version:
Severity: major Keywords:
Cc:

Description

The bug is described in http://www.ruby-forum.com/topic/39270#7479 and has stayed unanswered. I've just ran across this myself (on EdgeRails, Windows Server 2003, ruby 1.8.2).

<%= form_remote_tag :url => {:action => 'update_info', :id => @info} %>
  <%= render :partial => 'form' %>
  <%= submit_tag 'Edit', :name => 'update_button' %>
  <%= submit_tag 'Cancel', :name => 'update_button' %>
<%= end_form_tag %>

will produce a hash containing "update_button"=>"Edit" if you click the Edit button as well as on clicking the Cancel button. A change to form_tag produces the exspected behaviour ("update_button"=>"Cancel". Without explicity setthing the name to update_button the same occurs with the value of the "commit"-param.

regards Jan

Change History

12/19/05 19:34:08 changed by TwP

It looks like the Form.serialize() method from the prototype library is not figuring out which button is being pressed. It's just grabbing the first one it sees. For now, this workaround might be of interest ...

<%= form_remote_tag :url => {:action => 'update_info', :id => @info} %>
  <%= render :partial => 'form' %>
  <%= hidden_field 'update_button', 'Edit' %>
  <%= submit_tag 'Edit', :name => '_update_button' %>
  <%= submit_tag 'Cancel', :name => '_update_button',
                 :onclick => "Form.getInputs(this.form, null, 'update_button')[0].value = 'Cancel'" %>
<%= end_form_tag %>

04/04/06 16:53:54 changed by anonymous

Ugh that gets worse if you use RJS, cause I did not find a workaround. If anyone has one I would be happy to see a solution.

Thanks

04/14/06 10:22:10 changed by James Le Cuirot <chewi@aura-online.co.uk>

I had a look at Prototype to see if I could fix it there but I'm not sure if there's any way to detect which button was pressed without using onclick. It would be nice to make this work in a way where you could just blindly use submit_tag as usual.

http://www.faqts.com/knowledge_base/view.phtml/aid/2011/fid/129

04/14/06 11:23:30 changed by James Le Cuirot <chewi@aura-online.co.uk>

Here's an even simpler workaround that will allow you to keep your controller code the same for both AJAX and non-AJAX cases. It changes the names of the other buttons when you click. I tried to use this.value so you wouldn't have to repeat the value string but "this" doesn't seem to work in the context of the each function.

<%= submit_tag "Button 1", :name => 'my_button', :onclick => 'Form.getInputs(this.form, "submit").each(function(x) { if (x.value != "Button 1") x.name += "_"; })' %>
<%= submit_tag "Button 2", :name => 'my_button', :onclick => 'Form.getInputs(this.form, "submit").each(function(x) { if (x.value != "Button 2") x.name += "_"; })' %>

04/25/06 10:25:56 changed by Gerald S.

TwPs workaround didnt work for me (Rails 1.1.2) i use hidden_field_tag and because my form doesnt update itself i need an onclick-action on the first button as well

  <%= hidden_field_tag 'update_button', 'Apply' %>
  <%= submit_tag 'Apply', :name => '_update_button', :onclick => "Form.getInputs(this.form, null, 'update_button')[0].value = 'Apply'" %><br/>
  <%= submit_tag 'Reset', :name => '_update_button', :onclick => "Form.getInputs(this.form, null, 'update_button')[0].value = 'Reset'" %>

06/30/06 20:03:35 changed by blissdev@gmail.com

  • priority changed from normal to high.
  • milestone set to 1.x.

Is there any updates on this? I would love to see this fixed. I've been having problems with this, and many of the workarounds are inconsistent.

07/07/06 00:21:48 changed by sclaret@bccrc.ca

I work around this by replacing form_remote_tag with form_tag and using submit_to_remote rather than submit_tag.

It would be great if someone well-versed in the workings of Prototype could fix this bug at the source.

08/25/06 21:50:30 changed by myles@ducknewmedia.com.au

A slight modification to james' workaround:

<%= submit_tag 'Apply', :onclick => "Form.getInputs(this.form, 'submit').each(function(x) { if (x.value != this.value) x.name += '_'; }.bind(this))" %>

I've switch the string quoting around because rails was escaping the double quotes. Also used prototype's bind method to get access to the correct this object.

(in reply to: ↑ 11 ) 09/08/06 06:12:29 changed by rcarey@bu.edu

  • version deleted.
  • component changed from ActiveRecord to ActionPack.

Here's a solution I'm using, using the explicitOriginalTarget property of the submit event [Mozilla]. I don't believe that this property is supported by all browsers, and I don't believe there is a cross-browser equivalent, but there should be equivalent properties that can be substituted into the js using appropriate browser detection or whatever. I didn't have a need for that, though.

The nice thing is that it doesn't require any modification to the rhtml with onclick events or handlers.

from prototype.js:

--Form.serialize: function(form) {
++Form.serialize: function(form,ev) {
    var elements = Form.getElements($(form));
    var queryComponents = new Array();
++  if (typeof ev!='undefined')
++    elements.unshift(ev.explicitOriginalTarget);
      
    for (var i = 0; i < elements.length; i++) {
      var queryComponent = Form.Element.serialize(elements[i]);
      if (queryComponent)
        queryComponents.push(queryComponent);
    }
    return queryComponents.join('&');
  }

and in Rails, redefine ActionView::Helpers::PrototypeHelper.form_remote_tag

  def form_remote_tag(options = {})
--  options[:form] = true
++  options[:with] = "Form.serialize(this,event)"

    options[:html] ||= {}
    options[:html][:onsubmit] = "#{remote_function(options)}; return false;"
    options[:html][:action] = options[:html][:action] || url_for(options[:url])
    options[:html][:method] = options[:html][:method] || "post"

    tag("form", options[:html], true)
  end 

(in reply to: ↑ description ) 09/21/06 22:32:25 changed by eddie_roadcap

The following code placed in application_helper.rb or loaded via /lib works around this problem while allowing normal submit_tag() useage. This is not well tested, but seems to do the trick for me.

class ActionView::Base
  alias_method :rails_submit_tag, :submit_tag
  def submit_tag(value = "Save changes", options = {})
    options[:id] = (options[:id] || options[:name] || :commit)
    options.update(:onclick => "$('#{options[:id]}').value = 
'#{value}'")
    rails_submit_tag(value, options)
  end
end

So this template code:

   <%= submit_tag 'Transfer', :name => :submit %>
   <%= submit_tag 'Check IN' %>

produces this HTML:

   <input id="submit" name="submit" onclick="$('submit').value = 
'Transfer'" value="Transfer" type="submit">
   <input id="commit" name="commit" onclick="$('commit').value = 'Check 
IN'" value="Check IN" type="submit">

-Eddie

09/21/06 23:59:11 changed by bitsweat

We've got a lot of workarounds here - seems a definitive fix is elusive. If you wish to pursue it, please reopen with a patch+tests that thoroughly address the issue.

09/21/06 23:59:19 changed by bitsweat

  • status changed from new to closed.
  • resolution set to wontfix.