Creating multiselect fields?


#1

I am attempting to add some user fields based on the extend-user sprinkle: https://github.com/userfrosting/extend-user. The users in this site are all alumni of a school. One of the fields I want to add is a multiselect field to indicate any areas of expertise an alumni member might have. There are a whole slew of options and users should be able to have any number of them

I tried to add a simple select field with the “multiple” option specified to my template:

{% for area in job_areas %}
<option value="{{area}}" {% if (area == user.alum_job_area) %}selected{% endif %}>{{area}}
{% endfor %}

(“job_areas” is the list of options, defined in my controller and passed to this template.)

It displays fine in the modal window, and selected items are added to the field area as individual boxes. However, on submission, only the last one in the list is persisted to the database. I looked at the submitted form data in my browser, and these items shows up as several separate entries all with the key “alum_job_areas” – my guess is the earlier ones are overwritten in succession and so all that remains is the last one in the list.

The method that is called after submission is updateInfo in side of the native UserController, since I am extending that class.

Is there a way to ensure all the values are saved to the database? It shouldn’t be a SQL issue because this field has the “TEXT” type and so there’s not a character limit.


#2

Hi noonz,

Can you provide the rest of your code for the input element? (I think you just need to pass this input as an array).


#3

Yes I had tried that originally but then ran into validation errors later down the line. Here’s what I’ve done to get it to submit:

  1. Made the select field’s name into an array:
    <select id="input-alum-job-areas" class="form-control js-select2" name="alum_job_areas[]" multiple="multiple">
  1. Updated my edit-info.yaml file for this field to use the “array” rule (mentioned in the valitron docs but not the user frosting ones):
    alum_job_focus:
      validators:
        array:
          mesage: VALIDATE.NO_ARRAY
  1. After the modal is submitted, I was routing to UserFrosting\Sprinkle\ExtendUser\Controller\MemberController:updateInfo which was actually just the core UserController’s updateInfo since it extended the class, but now I overwrote it so I could process the array info. Specifically, in the capsule transaction, I added an if case to convert the array into a pipe delineated string:
// Begin transaction - DB will be rolled back if an exception occurs
    Capsule::transaction(function () use ($data, $user, $currentUser) {
      // Update the user and generate success messages
      foreach ($data as $name => $value) {
        if (is_array($value)) {
          $value = implode("|", $value);
        }
        if ($value != $user->$name) {
          $user->$name = $value;
        }
      }

      $user->save();
    ...
  1. Then when editing the user again, I had to modify how I was checking if certain elements were already selected. My options now look like this (note the “in” keyword for string comparison):
    <option value="{{area}}" {% if (area in user.alum_job_area) %}selected{% endif %}>{{area}}</option>

It works for my purposes, not sure if it’s the most elegant solution, and still not sure if it would be considered a bug.

  • With just the name change for the select field (step 1), I got validation errors saying that the field “contains invalid characters”
  • With the name change and the validation rule change (steps 1 and 2), the form submitted but all that was written to the database for that field was “Array”
  • With steps 1-3, the data submitted to the database, but would not show up in the field when editing that user again
  • With all the steps, it works as expected.

#4

Without knowing your requirements I am not sure if this is feasible, but if it is not necessary to have this field in the “edit user” modal, you could use a many-to-many relationship between users and expertise and then use ufCollection to handle the updates.


#5

Hmmmm I can look into it – I am relatively new to UserFrosting and this is the first customization I’ve tried to add. We do eventually want user entries to be searchable by any field, including this one, so I’m not sure if that would complicate the way searches would need to be done.


#6

I got cut short when I was writing my earlier post so just wanted to provide a little more information. The benefit of using a many-to-many relationship is that you would not have to be converting between a string and array. It also allows for all the convenient Eloquent methods to be used. For example, take a look at the sync method at
https://laravel.com/docs/5.4/eloquent-relationships#inserting-and-updating-related-models

If you decide to give it a try feel free to jump into chat or continue correspondence here with any more questions.