hoyhoy
hoyhoy

Reputation: 6351

Is it possible to call Javascript's onsubmit event programmatically on a form?

In Ruby on Rails, I'm attempting to update the innerHTML of a div tag using the form_remote_tag helper. This update happens whenever an associated select tag receives an onchange event. The problem is, <select onchange="this.form.submit();">; doesn't work. Nor does document.forms[0].submit(). The only way to get the onsubmit code generated in the form_remote_tag to execute is to create a hidden submit button, and invoke the click method on the button from the select tag. Here's a working ERb partial example.

<% form_remote_tag :url => product_path, :update => 'content', :method => 'get' do -%>
  <% content_tag :div, :id => 'content' do -%>
    <%= select_tag :update, options_for_select([["foo", 1], ["bar", 2]]), :onchange => "this.form.commit.click" %>
    <%= submit_tag 'submit_button', :style => "display: none" %>
  <% end %>
<% end %>

What I want to do is something like this, but it doesn't work.

<% form_remote_tag :url => product_path, :update => 'content', :method => 'get' do -%>
  <% content_tag :div, :id => 'content' do -%>
    # the following line does not work
    <%= select_tag :update, options_for_select([["foo", 1], ["bar", 2]]), :onchange => "this.form.onsubmit()" %>
  <% end %>
<% end %>

So, is there any way to remove the invisible submit button for this use case?

There seems to be some confusion. So, let me explain. The basic problem is that submit() doesn't call the onsubmit() code rendered into the form.

The actual HTML form that Rails renders from this ERb looks like this:

<form action="/products/1" method="post" onsubmit="new Ajax.Updater('content', '/products/1', {asynchronous:true, evalScripts:true, method:'get', parameters:Form.serialize(this)}); return false;">
  <div style="margin:0;padding:0">
    <input name="authenticity_token" type="hidden" value="4eacf78eb87e9262a0b631a8a6e417e9a5957cab" />
  </div>
  <div id="content">
    <select id="update" name="update" onchange="this.form.commit.click">
      <option value="1">foo</option>
      <option value="2">bar</option>
    </select>
    <input name="commit" style="display: none" type="submit" value="submit_button" />
  </div>
</form>

I want to axe the invisible submit button, but using a straight form.submit appears to not work. So, I need some way to call the form's onsubmit event code.

Update: Orion Edwards solution would work if there wasn't a return(false); generated by Rails. I'm not sure which is worse though, sending a phantom click to an invisible submit button or calling eval on the getAttribute('onsubmit') call after removing the return call with a javascript string replacement!

Upvotes: 7

Views: 14933

Answers (7)

FlySwat
FlySwat

Reputation: 175593

give your form an id.

then

document.getElementById('formid').submit();

If you are loading Javascript into a div via innerHTML, it won't run...just FYI.

Upvotes: 3

hoyhoy
hoyhoy

Reputation: 6351

In theory, something like eval ('function(){' + code + '}()'); could work (that syntax fails though). Even if that did work, it would still be sort of ghetto to be calling an eval through a select onchange. Another solution would be to somehow get Rails to inject the onsubmit code into the onchange field of the select tag, but I'm not sure if there's a way to do that. ActionView has link_to_remote, but there's no obvious helper to generate the same code in the onchange field.

Upvotes: -1

taiya
taiya

Reputation:

Not sure if you have an answer yet or not, but in the onclick function of the select, call onsubmit instead of submit.

Upvotes: 0

ErikE
ErikE

Reputation: 50211

I realize this question is kind of old, but what the heck are you doing eval for?

document.getElementById('formId').onsubmit();
document.getElementById('formId').submit();

or

document.formName.onsubmit();
document.formName.submit();

When the DOM of a document is loaded, the events are not strings any more, they are functions.

alert(typeof document.formName.onsubmit); // function

So there's no reason to convert a function to a string just so you can eval it.

Upvotes: 5

fatgeekuk
fatgeekuk

Reputation: 403

Don't.

You have a solution.

Stop, move on to the next function point.

I know, it is not pretty, but there are bigger problems.

Upvotes: 1

John Millikin
John Millikin

Reputation: 200796

If you have to use Rail's built-in Javascript generation, I would use Orion's solution, but with one small alteration to compensate for the return code.

eval ('(function(){' + code + '})()');

However, in my opinion you'd have an easier time in the long run by separating out the Javascript code into an external file or separate callable functions.

Upvotes: 2

Orion Edwards
Orion Edwards

Reputation: 123642

If you didn't actually want to submit the form, but just invoke whatever code happened to be in the onsubmit, you could possibly do this: (untested)

var code = document.getElementById('formId').getAttribute('onsubmit');
eval(code);

Upvotes: -3

Related Questions