6ft Dan
6ft Dan

Reputation: 2435

JavaScript generate Rails collection form from checkboxes and Submit (non-AJAX)

I'm building filters for a collection of Objects. I can't have a form over the whole page because I have smaller AJAX forms within the content and Rails doesn't allow forms inside forms. So I'm selectivng multiple profiles just fine in jQuery like so:

$(".profile-check:checked")

So now this is fine. But I want to do the following without a form.

<%= form_tag profile_ids_profiles_path, id: 'profile[profile_ids]', method: :patch do %>
  <div class="form-inline">
    <%= select_tag 'profile[command]', options_for_select(['delete']), include_blank: true, class: 'form-control input-group filters-select' %>
    <%= submit_tag 'submit', class: 'form-control input-group-addon btn filters-submit' %>
  </div>

<%# EACH profile has this %>
<%= hidden_field_tag "profile[profile_ids][]", '' %><%= check_box_tag "profile[profile_ids][]", profile.id, nil, class: "profile-check" %>

<% end %>

So I need to know how to generate the form params to send to Rails in the normal manner. Not with AJAX. A standard form submission without the HTML form. Only the params built within JavaScript/jQuery or CoffeeScript.

The params need to have the ID of the profile with the action being performed.

Parameters: {"utf8"=>"✓", "authenticity_token"=>"...", "profile"=>{"command"=>"delete", "profile_ids"=>["672", "674"]}}

Half solved:

Here's the JavaScript to create these exact parameters:

var formSend = new Object;
formSend["utf8"] = "✓";
var csrfName = $("meta[name='csrf-param']").attr('content');
var csrfValue = $("meta[name='csrf-token']").attr('content');
formSend[csrfName] = csrfValue;
formSend["profile"] = new Object;
formSend["profile"]["command"] = "delete";
formSend["profile"]["profile_ids"] = $(".profile-check:checked").map(
  function(){return this.value;}
).get();
JSON.stringify(formSend);

How do I send this data with a click as parameters for a regular form submission. Not AJAX/JS type submission, so that the server receives what it would expect from a normal web form submission.

Upvotes: 0

Views: 438

Answers (1)

6ft Dan
6ft Dan

Reputation: 2435

I found the 2nd half of the answer here: jQuery post request (not Ajax). Jeremy Banks gave some code he wrote which writes out an entire form from JSON and submits it. I've tested it and it works.

Here is the working code:

jQuery(function($) { $.extend({
  form: function(url, data, method) {
    if (method == null) method = 'POST';
    if (data == null) data = {};

    var form = $('<form>').attr({
      method: method,
      action: url
     }).css({
      display: 'none'
     });

    var addData = function(name, data) {
      if ($.isArray(data)) {
        for (var i = 0; i < data.length; i++) {
          var value = data[i];
          addData(name + '[]', value);
        }
      } else if (typeof data === 'object') {
          for (var key in data) {
            if (data.hasOwnProperty(key)) {
              addData(name + '[' + key + ']', data[key]);
            }
          }
      } else if (data != null) {
        form.append($('<input>').attr({
          type: 'hidden',
          name: String(name),
          value: String(data)
        }));
      }
    };

    for (var key in data) {
      if (data.hasOwnProperty(key)) {
        addData(key, data[key]);
      }
    }

    return form.appendTo('body');
  }
}); });
function filterCheckboxes(route, thing, cmd) {
  var formSend = new Object;
  formSend["utf8"] = "✓";
  formSend["_method"] = "patch";
  var csrfName = $("meta[name='csrf-param']").attr('content');
  formSend[csrfName] = $("meta[name='csrf-token']").attr('content');
  formSend[thing] = new Object;
  formSend[thing]["command"] = cmd;
  formSend[thing][thing + "_ids"] = $("." + thing + "-check:checked").map(
      function () {
        return this.value;
      }
  ).get();
  $.form(route, formSend, 'POST').submit();
}

And in the view:

<%= content_tag 'span', 'delete', class: 'filter-delete', onclick: "filterCheckboxes('#{profile_ids_profiles_path}', 'profile', 'delete')", style: 'cursor:pointer;' %>

I did end up needing to add formSend["_method"] = "patch"; since my routes have the method as PATCH. But it works well ^_^.

Upvotes: 0

Related Questions