0

I used to use a collection_select which makes a <select> with <options>.

  <%= f.label :members, class: "mdl-textfield__label" %>
  <%= f.collection_select :user_ids, User.where.not(id: current_user).collect, :id, :email, {include_hidden: false}, {:class => "mdl-textfield__input", :multiple => true} %>

Posts fine to the backend and it looks like this:

{"utf8"=>"✓",
 "authenticity_token"=>"redacted",
 "groupchat"=>{"topic"   =>"5dd",
               "user_ids"=>["5","6","7","8"]},
 "commit"=>"Done"}

Which is how I want it in my controller:

def groupchat_params 
  params.require(:groupchat).permit(:topic, {:user_ids => []}) 
end

PROBLEM: I am trying to recreate this functionality with an unordered list, ul with li, as that was the consensus for cross platform list pickers. Here is what I have:

      <ul id="special-select">
        <%= f.hidden_field :user_ids, { multiple: true, value: [] } %>
        <% User.where.not(id:current_user).each do |user| %>
          <li class="groupmember-select" id=<%= user.id %> value=<%= user.id %>>
            <%= user.name %>
          </li>
        <% end %>
      </ul>

I use a JavaScript variable to store the array as I select. All of that works, that is not the problem as far as I can tell and I don't want to clutter the question. I figure this is the case because the following is my script for the above .html.erb:

var user_ids = [];
$("#special-select li").click(function(){
  var index = user_ids.indexOf($(this).attr("value"));
  if (index > -1) {
    user_ids.splice(index, 1);
  }
  else {
    user_ids.push($(this).attr("value"));
  }
  $("#groupchat_user_ids").val(user_ids);
  $(this).toggleClass("selected");
});

When I select some items and check it out in the browser console, it looks to be in the form that I need it:

> user_ids
["2", "6", "3"]

However I noticed that when I right click on the object in the browser and paste it I get the following:

> user_ids
[0: "2", 1: "6", 2: "3", length: 3]

When I post the above form with the submit button I get the following (all items are in one string, separated by commas):

{"utf8"=>"✓",
 "authenticity_token"=>"redacted",
 "groupchat"=>{"topic"   =>"5dd",
               "user_ids"=>["5,6,7,8"]},
 "commit"=>"Done"}

I have tried JSON.stringify (output unchanged, looks the same as above) and JSON.parse (Almost like what I needed, but the escaped quotes were visible in the POST on the backend, regardless of that neither worked.

I had a very similar issue before, but it was before I had :user_ids defaulted to be an array.

Any insight would be great!

1 Answer 1

1

You can't pass an array with just one hidden field. What you need to do is add multiple hidden fields with the same name. The resulting HTML should look like this:

<input value="1" multiple="multiple" type="hidden" name="groupchat[user_ids][]">
<input value="2" multiple="multiple" type="hidden" name="groupchat[user_ids][]">
<input value="3" multiple="multiple" type="hidden" name="groupchat[user_ids][]">

So instead of changing the val to an array, you'll need to create multiple hidden tags and keep a track of them through javascript.

You can have a data-hidden-field-tag attribute on the li elements you are using and fetch them to store in place of user_ids array. Have a div of id hidden-fields or whatever you want inside the form, and update the div with hidden fields every time there is a change.

EDIT: Adding the code as per your application.

The HTML part.

<div id="hidden-fields" style="display: none;"></div>
<ul id="special-select">
  <% User.where.not(id: current_user.id).each do |user| %>
    <li class="groupmember-select" id=<%= user.id %> value=<%= user.id %> data-hidden-field-tag="<%= html_escape_once f.hidden_field(:user_ids, { multiple: true, value: user.id }) %>" >
      <%= user.identity %>
    </li>
  <% end %>
</ul>

The Javascript part:

var selectedUsers = [];
$("#special-select li").click(function(){
  var index = selectedUsers.indexOf($(this).attr("data-hidden-field-tag"));
  if (index > -1) {
    selectedUsers.splice(index, 1);
  }
  else {
    selectedUsers.push($(this).attr("data-hidden-field-tag"));
  }
  $("#hidden-fields").html(selectedUsers);
  $(this).toggleClass("selected");
});
Sign up to request clarification or add additional context in comments.

8 Comments

I tried to do this and I couldn't figure out the concept behind it. I do not want to submit EVERY value in the form. I want to only submit the ones that the user selects. Is the only way to do this to parse the string on the backend? How would you do that within my solution @Shobhit
Like how do you submit the array all at once like you do in a select? I don't want each on click event to trigger sending a POST.
But i don't understand how you select items from the list to be submitted in the form. Wouldn't your method just push all users in as selected users in the POST?
No, it uses the exact same method that you've used to select items. In place of you setting a value, I am just setting the hidden field as a whole. Give it a try, it worked for me.
But what does adding it to the div do? How to I submit the items I select in the form?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.