Laravel中点击搜索栏下拉选项填充表单的问题求助
问题描述
在Laravel 9(PHP 7.4+)项目中,基于Typeahead JS实现了MySQL数据库数据的搜索下拉功能,期望点击下拉结果时自动填充下方关联表单字段。目前搜索下拉可正常显示结果,但点击后无法填充表单,尝试过AJAX和Vue Axios方案均未解决。
相关代码
视图代码片段
<form method="POST" action="{{ route('incident.store') }}"> @csrf {{--* Injured Person --}} <div class="card"> <div class="card-header"> <i class="fa fa-align-justify"></i> {{ __('Injured Person') }} </div> <div class="card-body" id="app"> <div class="form-group row"> <label>Search CNIC</label> <div class="input-group"> <input class="form-control" type="text" placeholder="{{ __('Search CNIC') }}" name="ip_search_cnic" v-model='message' id="ip_cnic"> <div class=" input-group-append"> <button class="btn btn-primary" type="button" id="search_button" v-on:click=" searchInjuredPerson ">Search</button> </div> </div> <div class="form-group row"> <label>Name</label> <input class="form-control" type="text" placeholder="{{ __('Name') }}" name="ip_name" id="ip_name" v-model="injuredPerson.name" required autofocus> </div> <div class="form-group row"> <label>CNIC</label> <input class="form-control" type="text" placeholder="{{ __('CNIC') }}" name="ip_cnic" id="ip_cnic" v-model="injuredPerson.cnic" required autofocus> </div> <div class="form-group row"> <label>Address</label> <textarea class="form-control" name="ip_address" rows="9" id="ip_address" placeholder="{{ __('Address') }}" v-model="injuredPerson.address" required></textarea> </div> <div class="form-group row"> <label>Phone Number</label> <input class="form-control" type="tel" placeholder="{{ __('Phone Number') }}" name="ip_phone_number" id="ip_phone_number" v-model="injuredPerson.phoneNumber" required autofocus> </div> <div class="form-group row"> <label>Date of Birth</label> <input class="form-control" type="date" placeholder="{{ __('Date of Birth') }}" name="ip_date_of_birth" id="ip_date_of_birth" v-model="injuredPerson.dateOfBirth" required autofocus> </div> <div class="form-group row"> <label>Age</label> <input class="form-control" type="number" name="ip_age" id="ip_age" placeholder="{{ __('Age') }}" v-model="injuredPerson.age" required autofocus> </div> </div> </div> </form>
AJAX脚本
@section('javascript') <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script> $(document).ready(function() { // Handle search input keyup event $('#searchInput').keyup(function() { var searchCnic = $(this).val(); // Make an AJAX request to fetch matching injured persons $.ajax({ url: '/incident/search', type: 'POST', data: { ip_cnic: searchCnic }, success: function(response) { // Process the response and populate the dropdown list var dropdownList = $('#searchResults'); dropdownList.empty(); $.each(response, function(index, injuredPerson) { dropdownList.append($(' <option />', { value: injuredPerson.id, text: injuredPerson.cnic })); }); } }); }); // Handle dropdown selection change event $('#searchResults').change(function() { var selectedInjuredPersonId = $(this).val(); // Fetch the injured person details using AJAX $.ajax({ url: '/incident/' + selectedInjuredPersonId, type: 'GET', success: function(response) { // Populate the form fields with the retrieved data $('#ip_name').val(response.name); $('#ip_cnic').val(response.cnic); $('#ip_address').val(response.address); $('#ip_phone_number').val(response.phone_number); $('#ip_date_of_birth').val(response.date_of_birth); $('#ip_age').val(response.age); } }); }); }); </script> @endsection
路由配置(web.php)
//Showing dropdown for of fetched data by typehead Route::get('/home', [TypeaheadController::class, 'index']); Route::get('/autocomplete-search', [TypeaheadController::class, 'autocompleteSearch']); // For filling the form fields Route::post('incident/search', 'IncidentController@search')->name('incident.search'); Route::get('incident/{injured_person}', 'IncidentController@showPerson')->name('incident.show');
控制器代码
public function search(Request $request) { $cnic = $request->input('ip_cnic'); // Perform the search query $results = InjuredPerson::where('ip_cnic', 'LIKE', '%' . $cnic . '%')->get(); return response()->json($results); } public function showPerson(InjuredPerson $injured_person) { return response()->json($injured_person); }
问题现象
搜索下拉可正常显示匹配结果,但点击选项后表单字段无任何填充动作,无法实现自动拉取数据并填充表单的需求。
解决方案
核心问题排查
- DOM元素ID不匹配:脚本监听的
#searchInput、操作的#searchResults在视图中不存在;视图中存在两个id="ip_cnic"的元素,导致选择器失效。 - Vue与jQuery混用冲突:表单用Vue的
v-model绑定,但脚本用jQuery的val()赋值,Vue无法感知DOM手动修改,数据不同步。 - Typeahead事件未正确监听:未使用Typeahead原生的
typeahead:selected事件处理选项点击,而是错误监听普通select的change事件。
修复后代码示例
视图(修正ID冲突,添加Typeahead容器)
<form method="POST" action="{{ route('incident.store') }}"> @csrf {{--* Injured Person --}} <div class="card"> <div class="card-header"> <i class="fa fa-align-justify"></i> {{ __('Injured Person') }} </div> <div class="card-body" id="app"> <div class="form-group row"> <label>Search CNIC</label> <div class="input-group"> <!-- 修正搜索框ID为唯一值 --> <input class="form-control" type="text" placeholder="{{ __('Search CNIC') }}" name="ip_search_cnic" v-model='searchCnic' id="ip_search_cnic"> <div class="input-group-append"> <button class="btn btn-primary" type="button" v-on:click="searchInjuredPerson">Search</button> </div> </div> <!-- Typeahead下拉结果容器 --> <div id="typeahead-results" class="mt-2"></div> <div class="form-group row"> <label>Name</label> <input class="form-control" type="text" placeholder="{{ __('Name') }}" name="ip_name" id="ip_name" v-model="injuredPerson.name" required autofocus> </div> <div class="form-group row"> <label>CNIC</label> <!-- 修正CNIC输入框ID为唯一值 --> <input class="form-control" type="text" placeholder="{{ __('CNIC') }}" name="ip_cnic" id="ip_cnic_input" v-model="injuredPerson.cnic" required autofocus> </div> <div class="form-group row"> <label>Address</label> <textarea class="form-control" name="ip_address" rows="9" id="ip_address" placeholder="{{ __('Address') }}" v-model="injuredPerson.address" required></textarea> </div> <div class="form-group row"> <label>Phone Number</label> <input class="form-control" type="tel" placeholder="{{ __('Phone Number') }}" name="ip_phone_number" id="ip_phone_number" v-model="injuredPerson.phoneNumber" required autofocus> </div> <div class="form-group row"> <label>Date of Birth</label> <input class="form-control" type="date" placeholder="{{ __('Date of Birth') }}" name="ip_date_of_birth" id="ip_date_of_birth" v-model="injuredPerson.dateOfBirth" required autofocus> </div> <div class="form-group row"> <label>Age</label> <input class="form-control" type="number" name="ip_age" id="ip_age" placeholder="{{ __('Age') }}" v-model="injuredPerson.age" required autofocus> </div> </div> </div> </form>
Vue+Typeahead脚本(统一数据处理逻辑)
@section('javascript') <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.min.js"></script> <script> new Vue({ el: '#app', data: { searchCnic: '', injuredPerson: { name: '', cnic: '', address: '', phoneNumber: '', dateOfBirth: '', age: '' } }, mounted() { // 初始化Typeahead $('#ip_search_cnic').typeahead({ hint: true, highlight: true, minLength: 1 }, { name: 'cnics', source: (query, syncResults, asyncResults) => { // 异步请求搜索结果,携带CSRF令牌 axios.post('{{ route('incident.search') }}', { ip_cnic: query, _token: '{{ csrf_token() }}' }).then(response => { asyncResults(response.data); }); }, display: 'ip_cnic' // 指定显示的字段名 }).on('typeahead:selected', (event, selectedItem) => { // 选中选项后拉取详情并填充Vue数据 axios.get('{{ route('incident.show', '') }}/' + selectedItem.id) .then(response => { this.injuredPerson = { name: response.data.name, cnic: response.data.ip_cnic, address: response.data.address, phoneNumber: response.data.phone_number, dateOfBirth: response.data.date_of_birth, age: response.data.age }; }); }); }, methods: { searchInjuredPerson() { // 手动触发搜索下拉 $('#ip_search_cnic').typeahead('open'); } } }); </script> @endsection
控制器(优化返回字段)
public function search(Request $request) { $cnic = $request->input('ip_cnic'); // 仅返回Typeahead需要的字段 $results = InjuredPerson::select('id', 'ip_cnic') ->where('ip_cnic', 'LIKE', '%' . $cnic . '%') ->get(); return response()->json($results); } public function showPerson(InjuredPerson $injured_person) { // 返回表单需要的字段,与Vue数据对应 return response()->json([ 'name' => $injured_person->name, 'ip_cnic' => $injured_person->ip_cnic, 'address' => $injured_person->address, 'phone_number' => $injured_person->phone_number, 'date_of_birth' => $injured_person->date_of_birth, 'age' => $injured_person->age ]); }
路由(Laravel 9规范写法)
use App\Http\Controllers\TypeaheadController; use App\Http\Controllers\IncidentController; //Showing dropdown for of fetched data by typehead Route::get('/home', [TypeaheadController::class, 'index']); Route::get('/autocomplete-search', [TypeaheadController::class, 'autocompleteSearch']); // For filling the form fields Route::post('incident/search', [IncidentController::class, 'search'])->name('incident.search'); Route::get('incident/{injured_person}', [IncidentController::class, 'showPerson'])->name('incident.show');
关键注意事项
- 确保引入Typeahead官方库(
typeahead.bundle.min.js); - Laravel POST请求必须携带CSRF令牌,否则会被框架拦截;
- Vue数据字段需与控制器返回的JSON字段严格对应;
- 页面中所有DOM元素ID必须唯一,避免选择器冲突。
内容的提问来源于stack exchange,提问作者Ali Hassan
相关产品推荐
相关产品推荐

