【问题标题】:Laravel Select2 old input after validation验证后的Laravel Select2旧输入
【发布时间】:2016-08-12 00:23:28
【问题描述】:

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

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

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
            };
        }
    }
});

编辑

到目前为止,我发现的唯一(肮脏)解决方案如下:

 <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 是所有客户的列表,因此这意味着对于每个 Select2 框,我需要查询一个大的项目列表才能使其正常工作。如果我们谈论的是每个 Select2 框有数千行,这将是非常低效的。

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

【问题讨论】:

    标签: ajax laravel laravel-5 jquery-select2


    【解决方案1】:

    通常以编程方式设置 select2 的值,您会期望使用.val() 方法,然后使用.trigger('change') 调用as per their documentation(和other queries like this on SO)。但是,select2 本身在他们的文档中有一些关于 preselecting options for remotely sourced data 的内容。

    基本上他们的建议归结为(在初始化您的 AJAX 驱动 &lt;select&gt; 之后):

    • 使用预先选择的 ID 对新的 API 端点进行另一个 AJAX 调用
    • 在 AJAX 调用完成后,动态创建一个新选项并从 promise 函数 (.then()) 附加到底层 &lt;select&gt;
      • 也可以为此使用一些常规的 jQuery 回调链接函数
    • 触发change 事件
    • 触发select2:select 事件(并传递整个data 对象)

    假设您已经以多种方式将旧数据刷新到会话中,Laravel provides handy access to the previously requested input,尤其是这三种方式:

    • 通过Request 类进行静态访问,例如Request::old('customer') 在 OP 中
    • 全局old() helper 例如old('customer'),如果给定字段不存在旧输入,则返回 null,并且可以将默认值作为第二个参数
    • 在控制器的Request 实例上使用old() 方法,例如$request-&gt;old('customer')

    全局帮助方法通常建议在 Blade 模板中使用,就像这里的其他一些答案一样,当您不需要操纵值并且可以直接将其重新插入时很有用,您会带有文本输入之类的东西。

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

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

    无论哪种方式,在刀片模板处理任何内容之前,您都可以轻松获得特定数据(作为视图变量)。

    无论您选择如何注入数据,它仍然会遵循 select2 建议的模式:

    • 获取预选数据
    • 为其创建一个选项
    • 触发相应的事件

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

    【讨论】:

      【解决方案2】:

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

      控制器:-

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

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

      刀片视图:

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

      【讨论】:

        【解决方案3】:

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

        var oldCustomer = $('#customer > option[value={{ Request::old('customer') }}]');
        
        if (oldCustomer.length > 0) {
            oldCustomer.attr('selected', 'selected');
        }
        

        【讨论】:

        • 不起作用,因为这将在框中设置 ID 而不是关联的文本。请记住,select2 的数据如下所示: [id : ..., text: ...] 因此,您的解决方案会将 id 设置为选项的文本,而不是 id 的关联文本
        【解决方案4】:

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

        在控制器中:

        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'));
        }
        

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

        @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
        

        【讨论】:

          【解决方案5】:

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

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

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

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

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

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

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

          【讨论】:

          • 您的url: function() { 是在验证失败后页面重定向回来时调用,但您将如何留在 select2 预选框?
          【解决方案6】:

          如果我理解正确,我可以建议您为每个 select2 框隐藏输入 &lt;input type="hidden" name="customer_name" value="{{old('customer_name', '')}}"&gt;,在 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>
          

          【讨论】:

            【解决方案7】:

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

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

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

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

            按 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;
            });
            

            然后像 yrv 16s 回答:

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

            【讨论】:

              【解决方案8】:

              我用隐藏的文本输入来做到这一点,效果很好:

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

              表格:

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

              店内验证方法(控制器):

              $validator = Validator::make($request->all(), [
                          'item_id' => 'required',
                          'quantity' => 'required'
                      ]);
              
                      if ($validator->fails()) {
                          return redirect()
                              ->route('create_item', $order)
                              ->withInput($request->all())
                              ->withErrors($validator);
                      }
              

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

              【讨论】:

                【解决方案9】:

                你可以这样做:

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

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

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

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

                别忘了调用 select2 函数。

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

                最后在控制器中:

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

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

                祝你好运。

                【讨论】:

                  猜你喜欢
                  • 2013-10-13
                  • 2017-05-02
                  • 2016-06-12
                  • 2015-05-26
                  • 2015-05-13
                  • 1970-01-01
                  • 1970-01-01
                  • 2023-03-07
                  • 2017-05-02
                  相关资源
                  最近更新 更多