禁用的表单输入不会出现在请求中。

423

我在表单中有一些禁用的输入框,并且我想将它们发送到服务器,但是Chrome会将它们从请求中排除掉。

是否有任何解决方法可以避免添加隐藏字段?

<form action="/Media/Add">
    <input type="hidden" name="Id" value="123" />

    <!-- this does not appear in request -->
    <input type="textbox" name="Percentage" value="100" disabled="disabled" /> 

</form>

3
可能是禁用输入框的值不会被提交?的重复问题。 - Liam
4
@Liam,试图因为回答较少且质量较低的问题而支持关闭它,这是非常奇怪的尝试。 - hazzik
一个较早且不太受关注的问题。从技术上讲,当这个问题被提出时,它应该被关闭为重复问题。我已经向管理员标记了此问题以进行潜在合并,可能会或可能不会发生。这取决于他们。 - Liam
@Liam 实际上这些问题是不同的,即使有些答案看起来相似。我的问题是如何使“禁用”字段提交值,而另一个问题是关于“原因”的。 - hazzik
在我花费了几个小时试图解决它之后,我才到这里。嗯... - matcheek
为什么不直接将readOnly属性设置为true呢? - Nicolas Facciolo
13个回答

867
具有disabled属性的元素不会被提交,也可以说它们的值不会被发布(请参见构建表单数据集的HTML 5规范中第3步下的第二个要点)。

I.e.,

<input type="textbox" name="Percentage" value="100" disabled="disabled" /> 

参考HTML 4规范17.12.1

  1. 禁用的控件无法获得焦点。
  2. 在Tab键导航中跳过禁用的控件。
  3. 禁用的控件无法成功提交。

您可以在此情况下使用readonly属性,这样您就可以提交字段数据。

I.e.,

<input type="textbox" name="Percentage" value="100" readonly="readonly" />

供您参考,在HTML 4规范的17.12.2中:

  1. 只读元素可以被聚焦,但用户无法修改它们。
  2. 只读元素包含在Tab键导航中。
  3. 只读元素可以成功提交表单。

12
回答我的问题:不,只有 type='text'、type='password' 的<input/>表单控件和<textarea/>才能使用 readonly。readonly 的作用是防止用户更改控件的值。防止用户更改复选框(或 type='radio' 的输入)的值没有太多意义... - Muleskinner
5
您可以保留选择元素的 "disabled" 属性,但也可以添加另一个具有相同值的隐藏输入。 - talha2k
16
你是否曾经发现某些事情并想到:“他们到底是怎么想的,认为这很明显?”如果我费力地包括一个输入字段,其中可能启用或禁用,那意味着我不希望用户更改它,而不是它应该像根本没有被声明一样有效! - Nick Bedford
2
谢谢,这很有帮助,回答和回复都很好。 - user1449249
3
@NickBedford,特别是当您认为“哦,我可以通过添加禁用属性来快速且安全地处理这个问题。” - voracity
显示剩余5条评论

25

使用jQuery并使用ajax发送数据,您可以解决问题:

<script>

$('#form_id').submit(function() {
    $("#input_disabled_id").prop('disabled', false);

    //Rest of code
    })
</script>

1
这个解决方案的好处是,当用户在输入框上悬停时,你仍然可以使用红色禁用图标。+1 - Maduro
6
你可以使用CSS的cursor:not-allowed;来实现这个功能。 - sricks
@sricks 哦,真的吗?你能提供一个例子吗? - Maduro
1
我更喜欢使用这个解决方案,而不是使用"readonly",因为禁用的字段无法获得焦点。 - Andreas
1
请注意,如果 JavaScript 被关闭,此解决方案将无法使用。最好使用本机 HTML 的“readonly”功能。 - Sablefoste

13

如果要在提交表单时同时提交被禁用的输入值和启用的输入值,可以在提交表单时重新启用该表单中的所有输入元素。

<form onsubmit="this.querySelectorAll('input').forEach(i => i.disabled = false)">
    <!-- Re-enable all input elements on submit so they are all posted, 
         even if currently disabled. -->

    <!-- form content with input elements -->
</form>

如果您更喜欢使用jQuery:

<form onsubmit="$(this).find('input').prop('disabled', false)">
    <!-- Re-enable all input elements on submit so they are all posted, 
         even if currently disabled. -->

    <!-- form content with input elements -->
</form>

对于ASP.NET MVC C# Razor,您可以像这样添加提交处理程序:

using (Html.BeginForm("ActionName", "ControllerName", FormMethod.Post,
    // Re-enable all input elements on submit so they are all posted, even if currently disabled.
    new { onsubmit = "this.querySelectorAll('input').forEach(i => i.disabled = false)" } ))
{
    <!-- form content with input elements -->
}

jQuery选项中缺少一个引号。 - cagcak

9
如果您绝对需要禁用字段并传递数据,可以使用JavaScript将相同的数据输入到隐藏字段中(或者只设置隐藏字段)。这样即使您将数据发布到另一页,也可以将其禁用但仍然发布数据。

1
这个解决方案也是我一直在使用的 - 但正如我刚学到的那样 - readonly 属性是一个更好的解决方案。 - Muleskinner

6

我更新这个答案是因为它非常有用。只需在输入框中添加readonly属性。

所以表单将是:

<form action="/Media/Add">
    <input type="hidden" name="Id" value="123" />
    <input type="textbox" name="Percentage" value="100" readonly/>
</form>

4
语义上来说,这似乎是正确的行为。
我会问自己“我为什么需要提交这个值?
如果表单上有一个禁用的输入框,则可能不希望用户直接更改该值。
在禁用的输入框中显示的任何值都应该是
  1. 从生成表单的服务器上的值输出,或者
  2. 如果表单是动态的,则可以从表单上的其他输入计算出来。
假设处理表单的服务器与提供它的服务器相同,则复制禁用输入的值所需的所有信息都应该在处理中可用。
实际上,为了保持数据完整性,即使禁用输入的值已发送到处理服务器,您也应该进行验证。 这种验证需要与您需要复制值所需的相同级别的信息! 我几乎会认为只读输入框也不应该在请求中发送。
很高兴得到纠正,但我能想到的所有用例,其中需要提交只读/禁用的输入框的情况实际上只是伪装成样式问题

3
不要忘记它的价值可以直接通过Chrome开发者工具进行操纵。 - jimjim
总是很容易想象“我能想到的所有用例”等同于“所有可能的用例”。例如,想象一个动态表单,在某些条件下输入框可编辑,但在其他情况下被锁定以防止编辑。该输入框的值可能会更改,但由于某些条件发生而被禁用。尽管最终输入框被禁用,后端仍需要更新值。 - powderflask
@powderflask 我并没有想象我想到所有情况,这就是为什么我做出了区分。我猜可能会有一种游戏机制,在某些条件发生后希望停止值的增加... 并且仍然将其提交到后端;但是您仍然需要注意数据完整性和验证问题,因为这个值仍然可以被半熟练的用户操纵。 然而,大多数情况下,当输入变为禁用状态时,是因为它依赖于其他已更改的表单值.. 因此可以从中推断出。 - Arth
一个人永远不应该依赖客户端来对提交的POST数据进行消毒。禁用输入小部件无法防止具有中等能力的用户向该字段提交POST数据。责任始终在后台。我确实理解一般用例,只是对“我能想到的所有用例”提出了异议。HTTP可能因历史原因(例如,带宽有限,静态内容)而采用了这种方式,但这并不能使其在语义上正确。 - powderflask
@powderflask 是的,这正是我所说的要点,因为你必须在后端对输入进行清理 - 并且很可能可以从禁用输入的任何条件中推断出来 - 你可能不需要提交它。不期望/读取禁用的输入将保护您免受恶意用户提交有误数据的影响。好的,如果您有特定的用例需要您提交禁用的输入,则建议使用其他答案之一。这个答案更多的是“你是否问对了问题?” - Arth
@powderflask 是的,这正是我所要表达的观点,因为你无论如何都必须在后端对输入进行清理处理 - 而且很可能可以从禁用输入的条件推断出来 - 你可能不需要提交它。不期望/读取禁用的输入将保护你免受恶意用户提交错误数据的影响。好吧,如果你有一个特定的使用案例需要你提交禁用的输入,那么我建议你使用其他答案之一。这个答案更多地是一个“你是否提出了正确的问题?”的思考。 - Arth

3

我发现这个更容易实现:将输入框设置为只读,然后进行样式设计,以便最终用户知道它是只读的。在此处放置(例如从AJAX获取的)输入仍然可以提交,无需额外的代码。

<input readonly style="color: Grey; opacity: 1; ">

2

一个简单的解决方法是使用隐藏字段作为选择框、复选框和单选按钮的占位符。

从这段代码-

<form action="/Media/Add">
    <input type="hidden" name="Id" value="123" />

    <!-- this does not appear in request -->
    <input type="textbox" name="Percentage" value="100" disabled="disabled" /> 
    <select name="gender" disabled="disabled">
          <option value="male">Male</option>
          <option value="female" selected>Female</option>
    </select>

</form>

那段代码 -
<form action="/Media/Add">
    <input type="hidden" name="Id" value="123" />

    <input type="textbox" value="100" readonly /> 

    <input type="hidden" name="gender" value="female" />
    <select name="gender" disabled="disabled">
          <option value="male">Male</option>
          <option value="female" selected>Female</option>
    </select>
</form>

1

使用

<input type="textbox" name="" value="100" disabled/>

或者

<input type="textbox" name="" value="100" readonly/>

如果你正在使用像PHP Laravel这样的框架,没有name属性的元素将被视为未设置

<input type="textbox" value="100" disabled/>

0

我遇到了完全相同的问题,但是对我没有起作用,因为我选择了HTML元素,并且它的只读状态允许更改其值。因此,我在一种情况下使用select,在另一种情况下使用input:

   <% If IsEditWizard Then   %>
                            <%For Each item In GetCompaniesByCompanyType("ResponsibleEntity")%>
                            <% If item.CompanyCode.EqualsIgnoreCase(prCompany.GetAsString("LinkedCompany")) Then   %>
                            <input type="text" value="<%: item.CompanyName  %>" tabindex="3" size="12" maxlength="12" readonly="readonly" />
                            <input type="hidden" id="LinkedCompany" name="LinkedCompany" value="<%:item.CompanyCode %>" tabindex="3" size="12" maxlength="12" />
                            <%End If %>
                            <%Next %>
                            <%Else %>
                            <select id="LinkedCompany" name="LinkedCompany" class="w-auto" <%= If(IsEditWizard, "disabled", "") %>>
                                <option value="">Please Select</option>
                                <%For Each item In GetCompaniesByCompanyType("ResponsibleEntity")%>
                                <option value="<%:item.CompanyCode %>" <%: IIf(item.CompanyCode.EqualsIgnoreCase(prCompany.GetAsString("LinkedCompany")), "selected", String.Empty) %>><%: item.CompanyName %></option>
                                <%Next %>
                            </select>

                            <%End If %>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接