验证后 Laravel Select2 旧输入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36724902/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 13:38:08  来源:igfitidea点击:

Laravel Select2 old input after validation

ajaxlaravellaravel-5jquery-select2

提问by Markinson

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 Johnwould become 27in the selectbox. How can I get the text back?

我在我的网络应用程序中使用 Select2。我用 Ajax 加载我的 Select2 框。当验证失败时,除了 Select2 框外,所有输入都像以前一样填充。表单验证失败后如何恢复旧值?我的赌注是使用Request::old('x'),但这会插入值(在我的情况下是用户 ID)而不是所选文本。因此,例如文本John将成为27选择框。我怎样才能取回文本?

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

The js:

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>

$customersis 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.

$customers是所有客户的列表,所以这意味着对于每个 Select2 框,我需要查询一个大的项目列表才能使其工作。如果我们谈论每个 Select2 框有数千行,这将是非常低效的。

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

我想一定有更好的解决方案。谁能帮我?

回答by Leith

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.

通常以编程方式设置 select2 的值,您希望使用该.val()方法,然后根据他们的文档进行.trigger('change')调用(以及其他类似 SO 上的查询)。但是, select2 本身在他们的文档中有一些关于为远程来源数据预先选择选项的内容

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

基本上他们的建议归结为(在初始化你的 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 changeevent
  • trigger a select2:selectevent (and pass along the whole dataobject)
  • 使用预先选择的 ID 对新的 API 端点进行另一个 AJAX 调用
  • 在 AJAX 调用完成后,动态创建一个新选项并<select>从承诺函数 ( .then()) 附加到底层
    • 也可以为此使用一些常规的 jQuery 回调链接函数
  • 触发change事件
  • 触发select2:select事件(并传递整个data对象)

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

假设您已经将旧数据刷入到会话中,Laravel 提供了对先前请求输入的多种方式的便捷访问,特别是这三种方式:

  • static access via the Requestclass e.g. Request::old('customer')as in the OP
  • the global old()helpere.g. old('customer'), which returns nullif no old input for the given field exists, and can have a default as a second parameter
  • using the old()method on the Requestinstance from the controller e.g. $request->old('customer')
  • 通过Request类进行静态访问,例如Request::old('customer')在 OP 中
  • 全局old()助手eg old('customer')null如果给定字段的旧输入不存在,则返回,并且可以将默认值作为第二个参数
  • 使用控制器实例old()上的方法,Request例如$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.

全局助手方法更常被建议在 Blade 模板中使用,就像在此处的其他一些答案中一样,当您不需要操作值并且可以直接将其插入时非常有用,您可以使用类似的方法文本输入。

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):

最后一种方法可能为您提供了您正在寻找的答案 - 而不是从视图内部查询整个集合,您可以从控制器操作集合(类似于 OP,但应该更好,因为它不是在视图中解析它)或根据旧 ID 从控制器进行另一个查询并获取您想要的数据而无需拖网收集(更少的开销):

$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:

无论您选择注入数据,它仍将遵循 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).

唯一的区别是您不需要从另一个 API 端点获取数据(除非您出于其他编程原因想要/需要)。

回答by Shiro

I end up using similar flow like your. But my blade template is using htmlcollection package.

我最终使用了与您类似的流程。但是我的刀片模板使用的是 htmlcollection 包。

Controller:-

控制器:-

Let's say you are in create()method. When validation failed, it will redirect back to the create page. From this page, you can repopulate the list.

假设你在create()方法中。当验证失败时,它将重定向回创建页面。在此页面中,您可以重新填充列表。

$customer_list = [];
if(old('customer') != NULL){
    $customer_list = [old('customer') => $customers->where('id', old('customer'))->first()->name];        
}

Blade View:

刀片视图:

{{ Form::select('customer', $customer_list, null,  ['class' => 'searchselect searchselectstyle', 'id' => 'customer']) }}

回答by yrv16

If I understood you right I can recommend you to have for each your select2 box hidden input <input type="hidden" name="customer_name" value="{{old('customer_name', '')}}">where after change event for select2 you can insert selected name (etc. John). So if validation is fails you have:

如果我理解正确,我可以建议您为每个 select2 框隐藏输入<input type="hidden" name="customer_name" value="{{old('customer_name', '')}}">,在更改 select2 事件后,您可以插入选定的名称(等John)。因此,如果验证失败,您将拥有:

<select id="customer" name="customer" class="searchselect searchselectstyle">
@if(!is_null(old('customer')))
    <option value="{{old('customer')}}">{{old('customer_name')}}
   </option>
@endif
</select>

回答by Melissa

I did it with an input hidden for the text and it works well:

我使用隐藏文本的输入完成了它,并且效果很好:

This form is showed in a Popup and ajax (using Jquery-UJS)

此表单显示在 Popup 和 ajax 中(使用 Jquery-UJS)

Form:

形式:

<form action="{{ route('store_item', $order) }}" method="POST" data-remote="true">
    {{ csrf_field() }}
    <div class="form-group{{ $errors->has('item_id') ? ' has-error' : '' }}">
        <label class="control-label col-sm-2" for="item_id">Item: </label>
            <div class="col-sm-10">
                <select name="item_id" class="form-control" id="item_id">
                    @if(old('item_id')  != null)
                        <option value="{{ old('item_id') }}" selected="selected">
                            {{ old('item_title') }}
                        </option>
                    @endif
                </select>
            </div>
            {!! $errors->first('item_id', '<p class="text-center text-danger"<strong>:message</strong></p>') !!}
        </div>
        <input type="hidden" id="item_title" name ="item_title" value="{{ old('item_title') }}" />
        <div class="form-group{{ $errors->has('quantity') ? ' has-error' : '' }}">
            <label class="control-label col-sm-2" for="quantity">Cantidad: </label>
            <div class="col-sm-10">
                <input name="quantity" type="number" class="form-control" id="quantity" value="{{ old('quantity') }}"/>
            </div>
            {!! $errors->first('quantity', '<p class="text-center text-danger"><strong>:message</strong></p>') !!}
        </div>
        <button type="button" class="btn btn-default" data-dismiss="modal">Cancelar</button>
        <button type="submit" class="btn btn-primary" data-disable-with="Guardando...">Guardar</button>
    </form>


JAVASCRIPT:

爪哇脚本:

<script type="text/javascript">
        $(document).ready(function(){
            $('#item_id').select2({
                placeholder: 'Elige un item',
                ajax: {
                    url: '{{ route('select_item_data') }}',
                    dataType: 'json',
                    delay: 250,
                    processResults: function (data) {
                        return {
                            results:  $.map(data, function (item) {
                                return {
                                    text: item.title,
                                    id: item.id
                                }
                            })
                        };
                    },
                    cache: true
                }
            });

            $('#item_id').on('change', function(e){
                var title = $(this).select2('data')[0].text;
                $('#item_title').val(title);
            });
        });
    </script>


VALIDATION IN STORE METHOD (CONTROLLER):

存储方法验证(控制器):

$validator = Validator::make($request->all(), [
            'item_id' => 'required',
            'quantity' => 'required'
        ]);

        if ($validator->fails()) {
            return redirect()
                ->route('create_item', $order)
                ->withInput($request->all())
                ->withErrors($validator);
        }

It's very important to send 'withInput' and 'withErrors' in the redirection, because we are working with a popup and ajax that is created again and doesn't keep the old values.

在重定向中发送 'withInput' 和 'withErrors' 非常重要,因为我们正在使用重新创建的弹出窗口和 ajax 并且不保留旧值。

回答by soywod

Maybe you can try (once the ajax call has ended) :

也许您可以尝试(一旦 ajax 调用结束):

var oldCustomer = $('#customer > option[value={{ Request::old('customer') }}]');

if (oldCustomer.length > 0) {
    oldCustomer.attr('selected', 'selected');
}

回答by Gil

Same problem; I'm using a similar solution: If the old $id is set, I get the name and I use it as a variable for the view; Note that I also forward the id because I also used this method to pre-fill the form (coming from another place), but in this case, the name only should have been used, and for the id {{ old('author_id') }} can be used in the view:

同样的问题; 我正在使用类似的解决方案:如果设置了旧的 $id,则获取名称并将其用作视图的变量;请注意,我也转发了 id,因为我也使用此方法预先填写表单(来自另一个地方),但在这种情况下,应该只使用名称,并且对于 id {{ old('author_id' ) }} 可以在视图中使用:

In the controller:

在控制器中:

elseif (($request->old('author_id') !== null) && ($request->old('author_id') != '')) {
   $my_author_id = $request->old('author_id');
   $my_name = Author::find($my_author_id)->name;
   return view('admin/url_author.create', compact('my_name', 'my_author_id'));
}

And in the view (more precisely, in a partial used for creation & edition):

在视图中(更准确地说,在用于创建和编辑的部分中):

@if (isset($record)) // for use in edit case with laravelcollective)
   <select class="form-control js-data-author-ajax" id="author_id" name="author_id">
      <option value="{{ $record->author_id }}">{{ $record->author->name }}</option>
   </select>
@else
@if (isset($my_name)) // old input after validation + pre-filling cases
   <select class="form-control js-data-author-ajax" id="author_id" name="author_id">
      <option value="{{ $my_author_id }}">{{ $my_name }}</option>
   </select>
@else // for create cases
   <select class="form-control js-data-auteur-ajax" id="auteur_id" name="auteur_id">
      <option></option>
   </select>
@endif
@endif

回答by Srinath Reddy Dudi

Your code is bit confusing. I don't understand why you are using a POSTrequest to get data using ajax to fill a select2 box.

你的代码有点混乱。我不明白您为什么使用POST请求来使用 ajax 获取数据来填充 select2 框。

Assuming the datareturned using ajax call is in the below format.

假设data使用 ajax 调用返回的格式如下。

   [
     {
     "id": "Some id",
     "text": "Some text"
     },
     {
     "id": "ID 2",
     "text": "Text 2"
     },
    ]

Now what you can do is pass in an extra parameter to your ajax call as below

现在你可以做的是将一个额外的参数传递给你的 ajax 调用,如下所示

url: function() {
                    var type = $(this).attr('id');
                   @if(old('customer'))
                     return '/get' + type + '?customer='+ {{ old('customer') }};
                   @else
                     return '/get' + type;
                   @endif
                } 

Now in your controller while returning data you can throw an extra attribute selected:truefor an ID matching that particular ID.

现在在您的控制器中返回数据时,您可以selected:true为匹配该特定 ID 的 ID抛出一个额外的属性。

if( Request::has('customer') && Request::input('customer') == $id ) 
{
 [
 "id" => $id,
 "text" => $text,
 "selected" => "true"
 ]
}
else
{
 [
 "id" => $id,
 "text" => $text,
 ]
}

回答by Jamie

I think your own solution is pretty much correct. You say the list of $customers will get pretty big.

我认为您自己的解决方案非常正确。你说 $customers 的列表会变得很大。

$customers->where('id', intval(Request::old('customer')))->first()

Do you need to have the list stored in a variable $customers? You could just search the id you want

您是否需要将列表存储在变量 $customers 中?你可以只搜索你想要的id

App\Customer::where('id', intval(Request::old('customer')))->first()

Searching by id should not be inefficient. Otherwise you could send the name with the form and store it in the old request. Shown below with some (dirty) javascript.

按 id 搜索不应该是低效的。否则,您可以将名称与表单一起发送并将其存储在旧请求中。下面显示了一些(脏)javascript。

$("#form").submit( function() {
  var sel = document.getElementById("customer");
  var text= sel.options[sel.selectedIndex].text;
$('<input />').attr('type', 'hidden')
  .attr('name', "selected_customer_name")
  .attr('value', text)
  .appendTo('#form');
  return true;
});

Then like yrv 16s answer:

然后像 yrv 16s 回答:

<option value="{{old('customer')}}">{{old('selected_customer_name')}}

回答by Mahdi Younesi

You could do something like this:

你可以这样做:

First in controller pass tags to view using pluck helper like below:

首先在控制器中传递标签以使用 pluck helper 进行查看,如下所示:

public function create()
{
    $tags= Customer::pluck('name','name');

    return view('view',compact('tags'));
}

Then in your form try this:

然后在你的表格中试试这个:

   {!! Form::select('tag_list[]',$tags,old('tag_list'),'multiple','id'=>'tag_list']) !!}

Don't forget to call the select2 function.

不要忘记调用 select2 函数。

    $('#tag_list').select2();

And finally in controller:

最后在控制器中:

public function store(ArticleRequest $request)
 {
    $model = new Model;
    $tags=$request->input('tag_list');

    $model->tag($tags);
  }  

Noticetag function is not a helper in Laravel, You implement it! The function takes names and attaches them to the instance of some thing.

注意标签函数不是 Laravel 中的助手,你实现它!该函数采用名称并将它们附加到某些事物的实例上。

Good Luck.

祝你好运。