Use JS to change <form> from remote to non-remote in Rails 3, HAML
Asked Answered
I

2

17

The problem is that i have a remote form that, based on condition, id like to convert to a non-remote form (using UJS), and then submit. note the form has a file upload.

Here's the details: I have initially rendered the remote form using

= form_for @myobj, :url => {:action=>"remoteAction", :controller=>"myobjects"}, :remote => true do |f|
... (f.fields....)

which produces the HTML:

<form id="new_myobj" class="new_myobj" method="post" accept-charset="UTF-8" data-remote="true" action="/remoteAction">

when i click submit, as expected, the form is submitted 'AS JS'. in the controller action, i am doing some validation of the fields inside the submitted form. If all the validations pass, i execute the following .js.haml template:

$('form#new_myobj').removeAttr("data-remote");
$('form#new_myobj').attr('enctype', 'multipart/form-data');
$('form#new_myobj').attr('action', '/myobjects/regularAction');

which successfully changes the HTML on the page (witnessed via Firebug) to:

<form id="new_myobj" class="new_myobj" method="post" accept-charset="UTF-8" enctype="multipart/form-data" action="/myobjects/regularAction">

since the form contains an f.file_field, i have to submit as multipart so the image can be uploaded, and i cannot submit 'AS JS' now, when i click submit, the controller action 'regularAction' is indeed called, but its still 'AS JS'

the question is, what else do i need to change in the HTML so the form can be submitted non-xhr? is it related to the headers?

Inwrought answered 28/3, 2012 at 12:9 Comment(0)
P
42

jQuery is a bit tricky with the data attributes since it both reads the HTML5 data tags as well as its own storage bound to the DOM element, that is also called data. When writing to an attribute that value gets copied into jQuerys own data storage (presumably when data("remote") is being called).

However, this only happens if jQuery’s data is empty for that name. Thus setting the attribute will only work once, after that the "cached" value is being used even if the attribute changes. In order to really get rid of the value, we need to remove the attribute and jQuerys own storage method in that order. The reason is that there’s a high-level (element.removeData(…)) function and a low level one (jQuery. removeData(element, …)). The former re-reads the HTML5 data attribute and stores it in jQuery’s own storage. Using the rather unusual low level function obviously works as well.

Also, we do really need to remove the attribute -- setting it to false is not enough since Rails only checks if form.data('remote') is not undefined (look for it in jquery_ujs.js).

TL;DR:

  • attr("data-remote") != data("remote")
  • These two lines make a form non-remote (again). Order matters.
  $("form").removeAttr("data-remote");
  $("form").removeData("remote");

It’s documented, if you actually know what you’re looking for:

StackOverflow doesn’t allow me to post more than two links, but you can guess the removeData one. The high-level functions are linked from the low level ones.

Avoiding the token authenticity error in Rails 4+: As Stan commented below, just doing the above will fail with an InvalidAuthenticityToken error. The workaround is easy though, see here for details: https://mcmap.net/q/369369/-actioncontroller-invalidauthenticitytoken-when-disable-js-ajax-request

Parenteral answered 20/9, 2012 at 0:28 Comment(2)
By the way, this approach returns Can't verify CSRF token authenticity error in Rails 4.Tribalism
how about making the form remote again?Gelatin
F
4

The problem is that your approach to disable the Ajax submission isn't quite correct. You need to unbind the JavaScript events that have already been added by rails.js (Rails UJS adapter) to the form. You can do that by: $('form#new_myobj').unbind() to unbind all events attached to the form. You also need to $('form#new_myobj').removeAttr('data-remote') and $('form#new_myobj').removeAttr('data-type') to remove data-remote and data-type attributes (if existent).

Fixative answered 28/3, 2012 at 12:22 Comment(2)
Thanks for your suggestion, so i added the unbind() call to my js.haml template, but the 2nd submit still goes to the 'regularAction' action 'AS JS'Inwrought
is there any other component i need to unbind, perhaps?Inwrought

© 2022 - 2024 — McMap. All rights reserved.