Rails: cannot submit remote form loaded via Ajax

goal

I have a page with a list of items coming from the Rails backend. I want to be able to edit a line in this list using Ajax calls through Rails UJS.

An approach

I added an edit button to the end of each line. The edit button is link_to ... :remote => true . Clicking on it again loads the list, but with the selected line in edit mode. An editable line is embedded in form ... :remote => true . The save button on this line is the submit button.

index.html.haml

 #editor %table - @items.each do |item| %tr = render :partial => 'row', :locals => { :item => item } 

_row.html.haml

 ... %td // a number of columns with attributes ... %td = link_to t("actions.edit"), edit_item_path(item), :remote => true = link_to t("actions.delete"), item_path(item), :remote => true, :method => :delete, :data => { :confirm => "Are you sure?" } 

edit.html.haml

 #editor %table - @items.each do |item| %tr - if item == @item = form_for @item, :url => item_path(@item), :remote => true, do |f| = render :partial => "row_form", :locals => { :f => f } - else = render :partial => 'row', :locals => { :item => item } 

_row_form.html.haml

 ... %td // a number of columns with editable attributes ... %td %button{ :type => "submit" }=t("actions.save") = link_to t("actions.cancel"), items_path, :remote => true 

Ajax response handling

 $("#editor").on("ajax:success", function(event, data, status, xhr) { $("#editor").html($(data).find("#editor").html()); }); 

Problem

When I load the list page in edit mode /items/12/edit , the line item 12 is editable. Pressing the save button presents the form via Ajax correctly and loads the /items index partial, replacing the editable list with jQuery. Pressing the button, click the edit button again, reload the edit page (for example, /items/12/edit ), the inline form. Only this time, the form is no longer submitted when the save button is pressed. It seems that the submit event handler is not tied to a dynamically loaded remote form.

Question

How can I submit a remote form downloaded via Ajax, preferably using the Rails UJS approach?

Duplicates

I know that there are duplicates of this question, but none of them answered. Hope someone finally comes to a definite answer.

+6
source share
5 answers

I found a problem! Thanks to the tips in the answers of both @Jake Smith and @Parandroid. Here is what I found in two steps.

Search 1

When starting ajax:success , it seems not to be a problem, it seems that the form processing did not work 100% correctly only with the $("#editor") selector. At least it should be $("#editor form") , but it might not work if we start with an index page that does not yet contain a form. So the approach proposed by @Jake Smith seemed the most reliable way in the end. This led to:

edit.html.haml

 #editor = render :partial => "edit" 

edit.js.erb

 $('#editor').html('<%= escape_javascript render("edit") %>'); 

_edit.html.haml (still not working)

 %table - @items.each do |item| %tr - if item == @item = form_for @item, :url => item_path(@item), :remote => true, do |f| = render :partial => "row_form", :locals => { :f => f } - else = render :partial => 'row', :locals => { :item => item } 

But this did not lead to the creation of a working submit button. Until I found out what went wrong ...

Search 2

The above solution gave the submit button a simple old POST behavior that the server did not like, as it expected PUT reach the update action. Rails does this by creating a hidden _method field with a PUT value. I found out that rails generate this field (and a couple of other important hidden fields) on the very top of the _edit.html.haml part and not inside the form tag! So I moved the form to the beginning of the part, and it worked!

_edit.html.haml (WORK!)

 = form_for @item, :url => item_path(@item), :remote => true, do |f| %table - @items.each do |item| %tr - if item == @item = render :partial => "row_form", :locals => { :f => f } - else = render :partial => 'row', :locals => { :item => item } 

Who would have guessed ...

+1
source

How I worked is to use the built-in Rails function to do this:

  • In your controller edit action, add the format.js line to the respond_to line. This allows you to create an edit.js.erb file that you can use to load the edit form into the DOM.
  • Then, in the update action of the same controller, again add format.js to the respond_to and create the update.js.erb file, which performs the necessary manipulations with the DOM through jQuery.

I am sure that this is explained further in the tutorials on the Internet, but where I finally understood how it works without having to call jquery, the ajax methods were at CodeSchool.com .

+2
source

The problem is that the DOM was modified using javascript, and the callbacks (if ajax succeeded in your example) were initialized only in the DOM init. Therefore, when the DOM changed (in the #editor part), callbacks did not work.

So you shoul reinitialize this callback anytime you change the DOM with javascript

 $("#editor").on("ajax:success", function(event, data, status, xhr) { $("#editor").html($(data).find("#editor").html()); }); 

Some time ago, the jQuery function had a "live" function. It worked as "on", but tracked DOM changes. But in the current version of jQuery, this function is deprecated because it is slow.

I hope you understand my bad English =)

+2
source

I had a problem similar to the one in which the form downloaded via ajax was not submitted, it was related to Turbolinks, and I found a solution to connect my event with the body and not with the element, the corresponding answers are in this thread:

How to use $ (document) .on ("click .. on <tag?

For me, the problem was clicking on the label, so I had to change

$('label').click(function...

to

$('body').on('click', 'label', function

0
source

I had the same problem and finally understood the reason. Your html source should be generated as follows.

 <tr> <form> <td><input type="text"></td> <td><input type="submit"></td> </form> </tr> 

It seems that some browsers, including Chrome and Firefox, cannot correctly handle such nested tags.

I can successfully submit re-registered forms after replacing the table / tr / td tags with others, for example ul / li.

0
source

Source: https://habr.com/ru/post/945280/


All Articles