验证失败后的 Laravel 复选框状态

Posted

技术标签:

【中文标题】验证失败后的 Laravel 复选框状态【英文标题】:Laravel checkbox state after failed validation 【发布时间】:2018-06-01 10:14:53 【问题描述】:

关于如何在表单提交后正确保留 Laravel 中的复选框字段,这里有很多问题( example, example, example ),这个问题与此无关。

请注意,我也很了解Laravel's old() method,以及it accepts a default value。我的问题是关于 old() 似乎不适用于复选框的特殊情况。

我正在处理一个编辑表单,更新数据库中已有的数据。表单最初将使用数据库中的值填充。

验证失败后重新填充表单输入的标准方法是使用old()。对于大多数输入类型,类似以下的工作:

<input type='text' name='unicorns' value=' old('unicorns', $model->unicorns) '>

在初始页面加载时(在提交表单之前),这可以正常工作。由于尚未提交任何内容,old('unicorns')null,因此将使用默认的$model-&gt;unicorns,文本字段的值反映了当前的数据库状态。

在提交新值但验证失败后,old('unicorns') 将成为新值,即使新值是空字符串,并且文本字段的值再次反映了提交的状态,正如我们所愿。

但是,当未选中的复选框根本没有出现在请求中时,这会破坏复选框。考虑:

<input type='checkbox' name='unicorns' value='1' @if old('unicorns', $model->unicorns) checked @endif>

在初始页面加载时,这工作正常,就像文本字段一样。但在验证失败后,对于复选框从初始状态更改的两种情况:

案例 1:DB 状态 0(未选中),已提交状态已选中。 old('unicorns') 将是 1,所以测试评估 true,复选框被选中 - OK!

案例 2:DB 状态 1(选中),未选中提交状态。由于old('unicorns') 为空,old() 回退到默认值$model-&gt;unicorns (1),所以测试评估true,并且复选框被选中 - 但我们只是取消选中它!失败!

(其他2种情况没有问题,复选框没有从DB中的状态改变)。

如何解决?

我最初认为解决此问题的最佳方法是测试是否存在验证错误 - 如果是,请使用 old() 值,没有默认回退;如果没有,请使用 old() 和默认后备。测试验证失败的一种方法是检查$errors。这似乎可行,但它only works within a view AFAICT,如(来自 Laravel 文档):

注意:$errors 变量绑定到视图...

我想为此创建一个全局帮助器,而 $errors 不会在那里工作。无论如何,这种方法感觉......笨重且过于复杂。

我错过了什么吗?有没有一种简洁的 Laravel 方法来解决这个问题? old() 根本不适用于这种特殊情况,这似乎很奇怪。

这不是一个新问题,其他人是如何处理的?

【问题讨论】:

您使用的是哪种表格?是编辑表单还是新的空表单? @Shubhampokhriyal 这是一个编辑表单;我认为这个问题已经说明了这一点(现有值 $model-&gt;unicorns 混合在一起等),但我已经对其进行了更新以使其更加清晰。 @Shubhampokhriyal 好的 - 你能解释一下吗?验证失败后如何使用新状态重新填充复选框? 好的,我找到了一个链接,这可能会有所帮助***.com/questions/23762841/… @Shubhampokhriyal 这描述了在文本字段上使用old(),使用表单模型绑定。我没有使用这些东西。 【参考方案1】:

这是我在问题中提到的解决方案。它运作良好,6 个月后,它似乎不像我发布问题时那样笨拙。不过,我很高兴听到其他人是如何做到这一点的。

我有一个html 助手,创建为described in this question,别名为config/app.php,如this answer to that question 的第一部分所述。我给它加了一个静态方法:

namespace App\Helpers;
use Illuminate\Support\ViewErrorBag;

class Html 
    /**
     * Shortcut for populating checkbox state on forms.
     *
     * If there are failed validation errors, we should use the old() state
     * of the checkbox, ignoring the current DB state of the field; otherwise
     * just use the DB value.
     *
     * @param string $name The input field name
     * @param string $value The current DB value
     * @return string 'checked' or null;
     */
    public static function checked($name, $value) 
        $errors = session('errors');

        if (isset($errors) && $errors instanceof ViewErrorBag && $errors->any()) 
            return old($name) ? 'checked' : '';
        

        return ($value) ? 'checked' : '';
    

现在在我看来,我可以这样使用它:

<input type='checkbox' name='unicorns' value='1'  \Html::checked('unicorns', $model->unicorns) >

这会在初始加载和验证失败后正确处理数据库和提交状态的所有组合。

【讨论】:

【参考方案2】:

我遇到了同样的问题,发现了这个旧帖子。想分享我的解决方案:

<input type="checkbox" name="unicorns" class="form-check-input" id="verified"  !old()?$model->unicorns:old('unicorns')?' checked':'' >

 !old()?$model->unicorns:old('unicorns')?' checked':'' 

嵌套三元组:第一个三元组为第二个提供条件:

当没有old()数组时,就没有post,因此DB值$model-&gt;unicorns将被用作这样的条件:

$model-&gt;unicorns?' checked':'' 将正确评估 0 或 1 的值

如果存在old() 数组,我们可以使用old('unicorns') 变量的存在作为条件,如下所示:

old('unicorns')?' checked':'' 将正确评估 on 的值或无值。

这是一种类型的杂耍,你有嵌​​套的三元,但效果很好。

【讨论】:

【参考方案3】:

我有类似的情况,我的解决方案是在复选框字段之前添加一个隐藏字段。所以,在你的情况下,它会是这样的:

<input type='hidden' name='unicorns' value='0'>
<input type='checkbox' name='unicorns' value='1' !! old('unicorns', $model->unicorns) ? ' checked' : '' !!>

这样,当未勾选复选框时,该字段的值 0 仍将出现在发布请求中。当它被勾选时,复选框的值将覆盖隐藏字段中的值,因此顺序很重要。您不需要通过这种方法使用自定义类。

这对你有用吗?

【讨论】:

感谢您的尝试,但不,这根本不能回答问题。问题的第一句话描述了我不是在问你回答的问题。问题是关于在前端正确维护复选框状态,这个答案没有解决这个问题。 嗯,很公平,抱歉我帮不上忙 :-)【参考方案4】:

根据 Don't Panic 的回答,您可以在刀片中这样做:

<input type="checkbox" class="form-check-input" value='true'
@if ($errors->any())
 old('is_private') ? 'checked' : '' 
@else
 isset($post) && $post->is_private ? 'checked' : '' 
@endif
>

希望对你有帮助。

【讨论】:

【参考方案5】:

我这样做

 <input id="main" class="form-check-inline"
 type="checkbox" name="position" old('position',$position->status)?'checked':''>

【讨论】:

AFAICT 这失败的方式与我在问题中描述的案例 2 完全相同。如果数据库状态为1(选中),并且您取消选中复选框,然后提交,如果验证失败并返回表单,此代码将有复选框选中 i>,这是不正确的 - 您只是未选中它。这不起作用?【参考方案6】:

在持久化复选框状态时,我实际上做了一个简单的三元运算符:

<input name='remember' type='checkbox' value='1'  old('remember') ? 'checked' : '' >

编辑:

<input name='remember' type='checkbox' value='yes'  old('remember') == 'yes' ? 'checked' : '' >

【讨论】:

但这不会设置初始状态,无论数据库中当前的值是什么,对吧? 当然,当您处理存储在数据库中的值时,您必须对其进行一些调整。我为您提供了一个通常以create 形式使用的示例。如果您想检索记录,则显示一个 edit 表单,您只需将其更改为 old('remember', YOUR_VALUE) 感谢您的意见,但我不确定您是否完全阅读或理解了这个问题。我描述了为什么使用您描述的默认值不起作用。我很想被证明我错了,如果你能告诉我请做,这就是我在这里的原因! :-) 。就目前而言,您的回答和评论表明您还没有理解这个问题。 我认为最好的方法是用字符串替换值。类似&lt;input name='remember' type='checkbox' value='yes' old('remember', YOUR_VALUE) == 'yes' ? 'checked' : '' '&gt; 该值是字符串还是 int 没有区别。如果未选中,它仍然会完全从请求中丢失,这是问题的根源。

以上是关于验证失败后的 Laravel 复选框状态的主要内容,如果未能解决你的问题,请参考以下文章

使用 Laravel 和 Passport 在身份验证失败时响应状态码 401?

验证后的Laravel Select2旧输入

Laravel 验证:检查验证器失败的原因

Codeigniter:选中复选框时表单验证仍然失败

Laravel 5 更改表单请求失败的验证行为

Laravel 验证登录表单验证在密码确认中失败?