Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel Select2 old input after validation

I'm using Select2 in my webapplication. I load my Select2 boxes with Ajax. When validation fails, all the inputs are filled as before except the Select2 box. How can I restore the old value after the form validation fails? My bet was using Request::old('x'), but this inserts the value (in my case an user ID) instead of the selected text. So for example the text John would become 27 in the selectbox. How can I get the text back?

<select id="customer" name="customer" class="searchselect searchselectstyle">
</select>

The js:

token = '{{csrf_token()}}';

$(".searchselect").select2({
    ajax: {
        dataType: "json",
        type: "POST",
        data: function (params) {
            return {
                term: params.term,
                '_token': token,
                'data' : function(){
                    var result = [];
                    var i = 1;
                    $('.searchselect').each(function(){
                        result[i] = $(this).val();
                        i++;
                    });
                    return result;
                }
            };
        },
        url: function() {
            var type = $(this).attr('id');
            return '/get' + type;
        },
        cache: false,
        processResults: function (data) {
            return {
                results: data
            };
        }
    }
});

Edit

The only (dirty) solution I found so far is the following:

 <select id="customer" name="customer" class="searchselect searchselectstyle">
    @if(Request::old('customer') != NULL)
        <option value="{{Request::old('customer')}}">{{$customers->where('id', intval(Request::old('customer')))->first()->name}}</option>
    @endif
</select>

$customers is a list of all customers, so this means that for each Select2 box I need to query a big list of items in order to make it work. This will be pretty inefficient if we're talking about thousands of rows per Select2 box.

I guess there must be a better solution. Who can help me?

like image 581
Markinson Avatar asked Apr 19 '16 17:04

Markinson


1 Answers

Normally to programmatically set the value of a select2, you would expect to use the .val() method followed by a .trigger('change') call as per their documentation (and other queries like this on SO). However, select2 themselves have something in their documentation about preselecting options for remotely sourced data.

Essentially their suggestion boils down to (after initalizing your AJAX-driven <select>):

  • make another AJAX call to a new API endpoint using the pre-selected ID
  • dynamically create a new option and append to the underlying <select> from a promise function (.then()) after the AJAX call is finished
    • could also use some of the regular jQuery callback chaining functions for this
  • trigger a change event
  • trigger a select2:select event (and pass along the whole data object)

Assuming you're already flashing the old data to the session, Laravel provides handy access to the previously requested input in a variety of ways, notably these three:

  • static access via the Request class e.g. Request::old('customer') as in the OP
  • the global old() helper e.g. old('customer'), which returns null if no old input for the given field exists, and can have a default as a second parameter
  • using the old() method on the Request instance from the controller e.g. $request->old('customer')

The global helper method is more commonly suggested for use inside Blade templates as in some of the other answers here, and is useful when you don't need to manipulate the value and can just plug it straight back in, which you would with things like text inputs.

The last method probably provides you with the answer you're looking for - instead of querying the entire collection from inside of the view, you're able to either manipulate the collection from the controller (similar to the OP, but should be nicer since it's not parsing it in the view) or make another query from the controller based on the old ID and fetch the data you want without having to trawl the collection (less overhead):

$old_customer = Customer::find($request->old('customer'));

Either way, you'd have the specific data available at your fingertips (as a view variable) before the blade template processes anything.

However you choose to inject the data, it would still follow the pattern suggested by select2:

  • get the pre-selected data
  • create an option for it
  • trigger the appropriate events

The only difference being you don't need to fetch the data from another API endpoint (unless you want/need to for other programmatic reasons).

like image 133
Leith Avatar answered Sep 18 '22 17:09

Leith