0
votes

I have a rails view page that displays a table with each row being a user update form. To submit a form, you must select a "submit form" checkbox. The checkbox then adds "submittable" to that form's class list. When the "update all" button is pressed, it uses jquery to return a collection of all forms with "submittable" class, then iterates through each form and submits them using jquery's submit() function. This is all fine and good and works as expected.

The issue comes when the user status filter function is used. The status filter allows you to click a certain user status, then links you back to the controller action with the user status given as a param. Using a debugger, I can see that this request hits the expected controller action and loads the page with the selected users as expected.

However - after using the status filter option, the "update all" button no longer works. It tries to submit a "post" request and returns a "no route found" error. Update function will only work after refreshing the page.

Inspecting the page, it looks as though the form would be as you expect, identical to a submission on a fresh page load, with all inputs present and correctly nested including the hidden "patch" input. Using a debugger in the submitAll function however reveals that the elem to be submitted no longer contains any form inputs, and inspecting the Network tab, under Headers, doesn't show me any form data being submitted. I thought the issue may be caused by the jquery submit(), but when I add a f.submit input this also fails after using the status filterer. It doesn't even send a request, nothing happens when you click the button at all.

Any ideas as to what could be breaking my form submit?

Here is the view containing the status filterer and the form:

- status_options = User::SEARCH_STATUS_RANKING
  - status_options.each do |status|
    = link_to status, admin_unhandled_deposits_positive_enterprise_settlements_path(params.merge(status: status)), class: ['status', status]

button#update_all_button
   | Update

= simple_form_for user, url: update_user_status_admin_user_url(user), method: :patch, remote: true do |f|
    = f.simple_fields_for :review_reason do |rr|
        = f.input :status, label: false, collection: row[:statuses_for_select], include_blank: false
        = rr.input :reason_type, label: false, collection: review_reasons, required: true 
        = check_box_tag :form_submit, true, false, id: "submit_checkbox"


javascript: 

var submitCheckbox = document.getElementById("#submit_checkbox");
        submitCheckbox.addEventListener('change', selectFormForSubmit);
        const thisForm = document.getElementById("#status_form");

        function selectFormForSubmit() {
            if (this.checked) {
                thisForm.classList.add('submittable')
            } else {
                thisForm.classList.remove('submittable')
            }
        }
var submitAllButton = document.getElementById("update_all_button");
submitAllButton.addEventListener('click', submitAll);

function submitAll() {
    $('.submittable').each( function(index, value){
      const elem = $(value);
      elem.trigger('submit.rails');
    })
  }

This is the controller action:

  def positive_enterprise_settlements
    report_date = params[:settlements_created_on] || Date.today
    @report = PositiveEnterpriseSettlementsReport.new(settlements_created_on: report_date, user_status: params[:status])
    @report.build
  end
1

1 Answers

0
votes

There are two big issues here. The first is that id="submit_checkbox" may not be unique on the page. Instead use classes to hook your JavaScript onto.

The second is that this JavaScript is non-idempotent - you're attaching event handlers directly to the elements so that when the page content is replaced by turbolinks or any other ajax request the handlers are gone with elements you attached them to.

That's why it works on the intial page load and then only works when you reload the page. Instead you want to create delegated handlers that are attached to the document. You also don't really need have a handler that adds the classes to the form. Just check the value of the checkboxes when looping through the forms instead.

= simple_form_for user, url: update_user_status_admin_user_url(user), method: :patch, remote: true, html: { class: "my-special-form"} do |f|
    = f.simple_fields_for :review_reason do |rr|
        = f.input :status, label: false, collection: row[:statuses_for_select], include_blank: false
        = rr.input :reason_type, label: false, collection: review_reasons, required: true 
        = check_box_tag :form_submit, true, false
function submitAll() {
  $('.my-special-form').each(function(){
    if (this.elements["form_submit"].checked){
      $(this).trigger('submit.rails');
    }
  });
}

$(document).on('click', '#update_all_button', submitAll);

IMHO I don't get why you're doing this in the first place since you're doing N number of ajax calls anyways. Why not just have a button on each form that submits it instead of making the user jump though an additional hoop?