laravel 的 old() 不自动回填 select,需手动为 option 添加 selected 属性;select 标签的 value 属性无效,因 html 规范不支持;正确写法是 us。

直接说结论:Laravel 的 old() 不是“自动回填所有表单控件”的万能函数,它只返回值,不操作 DOM;
为什么 <select value="{{ old('country') }}"></select> 不起作用
HTML 规范明确要求:<select></select> 本身没有 value 属性语义,浏览器会忽略它;选中状态只能由其子元素 <option selected></option> 控制。Laravel 的 old() 只是从 session 里取字符串(比如 "US"),它不会、也不能自动往某个 <option></option> 上加属性。
- 常见错误现象:下拉框始终默认选中第一项,或完全没高亮
- 典型误写:
<select name="country" value="{{ old('country') }}"></select>—— 这行代码应整行删除 - 根本原因:把
<input>的逻辑套用到<select></select>上,混淆了“值存储”和“DOM 状态控制”两个层面
old('country') == $code ? 'selected' : '' 怎么写才安全
这是唯一可靠的手动同步方式,但要注意三处细节:
- 比较必须在
<option></option>标签内完成,例如:<option value="{{ $code }}" old :>{{ $name }}</option> - 使用
==而非===更稳妥——old()返回字符串,而数据库或配置里的键可能是整数(如1表示中国),宽松比较能兼容类型差异 - 空选项(如 “请选择”)必须显式处理:
<option value="" old :>{{ __('Select a country') }}</option>,否则当用户未选择时,旧值为null或空字符串,不加判断会导致无选项被选中
复用 @include 组件时怎么传 old() 值
如果国家列表抽成了 @include('layouts.country-list'),就不能指望子视图自动知道当前要匹配哪个旧值——old() 是全局辅助函数,但子视图无法“感知”父级字段名。
- 正确做法:显式传参,例如
@include('layouts.country-list', ['field' => 'country', 'selected' => old('country')]) - 子视图中改用
{{ $selected == $code ? 'selected' : '' }},避免硬编码字段名 - 若仍用
old('country')写死在子视图里,一旦父级字段名改成nationality,子视图就失效,且难以调试 - 性能影响为零,但可维护性差:每次改字段名都要同步修两个地方
最容易被忽略的一点:验证失败后重定向,old() 值只存在一次,且依赖 session 正常写入。如果控制器里用了 return redirect()->back()->withInput($request->except('password')) 却忘了在路由中确认该路由属于 web 中间件组,session 就不会生效,old() 永远返回 null。











