【问题标题】:HTML form readonly SELECT tag/inputHTML 表单只读 SELECT 标记/输入
【发布时间】:2021-08-29 15:25:54
【问题描述】:

根据 HTML 规范,HTML 中的select 标签没有readonly 属性,只有disabled 属性。所以如果你想让用户不改变下拉菜单,你必须使用disabled

唯一的问题是禁用的 HTML 表单输入不会包含在 POST / GET 数据中。

模拟select 标记的readonly 属性并仍然获取POST 数据的最佳方法是什么?

【问题讨论】:

  • 服务器端不要依赖它。任何人都可以创建自己的 HTML 页面并将其设为 RW。
  • 但这不是 PHP 特有的问题。
  • 我建议在这种情况下根本不要使用选择元素。有什么理由不能将值显示为纯文本?
  • @ppumkin 您的评论毫无意义。我并不是说选择或隐藏表单字段从来没有一个好的用例。 OP 在页面上显示一些文本时遇到问题,我只是想知道在这种情况下使用 select 元素的目的是什么。
  • 我一定是读错了问题。他说他想禁用选择,这样用户就不会改变它。也许他需要使用选择来呈现页面并使用 jquery 来防止更改。但是当他提交回来时,没有任何数据。我也在做同样的事情。我需要显示由其他选择过滤的选择,最后一个下拉菜单通过 ajax 保存到数据库,因此必须锁定之前的所有选择。当我重新渲染页面时,是的,好的——我可以显示标签而不是选择。但这不是问题:)

标签: javascript html


【解决方案1】:

您可以在提交时重新启用选择对象。

编辑:即通常禁用选择标签(使用 disabled 属性),然后在提交表单之前自动重新启用它:

jQuery 示例:

  • 禁用它:

    $('#yourSelect').prop('disabled', true);
    
  • 在提交之前重新启用它,以便包含 GET / POST 数据:

    $('#yourForm').on('submit', function() {
        $('#yourSelect').prop('disabled', false);
    });
    

此外,您可以重新启用每个禁用的输入或选择:

$('#yourForm').on('submit', function() {
    $('input, select').prop('disabled', false);
});

【讨论】:

  • 使用 .prop('disabled',true/false) 来设置 disabled 属性。该属性不会改变实际状态。
  • 我认为这个解决方案比@bezmax 解决方案聪明。因为如果我们添加隐藏输入,我们必须考虑到每个输入(同名)在任何时候都只有一个启用。否则,如果启用了两个输入,则在服务器端,程序将采用可能导致异常的输入数组(例如,如果我们没有处理这种情况,并且我们期望一个字符串并使用 'Request.Form[FieldName] ' 命令)
  • @Kevin,工作 > 90% 的案例。此外,你必须有 jquery 在你的腰带......嗯。
  • 这是公认的答案更清晰。如果您不想再禁用元素并且不需要额外的输入标签,则更容易撤消逻辑。
  • 你拯救了我的一天!我正在寻找与此类似的解决方案。我的 Spring Boot 应用程序中总是出现 NullPointerException。非常感谢! :)
【解决方案2】:

您应该保留select 元素disabled,但还要添加另一个具有相同名称和值的隐藏input

如果您重新启用您的 SELECT,您应该将其值复制到 onchange 事件中的隐藏输入并禁用(或删除)隐藏输入。

这是一个演示:

$('#mainform').submit(function() {
    $('#formdata_container').show();
    $('#formdata').html($(this).serialize());
    return false;
});

$('#enableselect').click(function() {
    $('#mainform input[name=animal]')
        .attr("disabled", true);
    
    $('#animal-select')
        .attr('disabled', false)
    	.attr('name', 'animal');
    
    $('#enableselect').hide();
    return false;
});
#formdata_container {
    padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
    <form id="mainform">
        <select id="animal-select" disabled="true">
            <option value="cat" selected>Cat</option>
            <option value="dog">Dog</option>
            <option value="hamster">Hamster</option>
        </select>
        <input type="hidden" name="animal" value="cat"/>
        <button id="enableselect">Enable</button>
        
        <select name="color">
            <option value="blue" selected>Blue</option>
            <option value="green">Green</option>
            <option value="red">Red</option>
        </select>

        <input type="submit"/>
    </form>
</div>

<div id="formdata_container" style="display:none">
    <div>Submitted data:</div>
    <div id="formdata">
    </div>
</div>

【讨论】:

  • 如果您重新启用选择,您当然还必须禁用或删除隐藏的输入(在复制它的值之后)。否则你会得到双倍提交的值
  • @max 啊!。好的,这也有效。自从你说隐藏的输入应该与选择的名称具有“相同的名称”之后,我就假设了。
  • 如果我使用多选怎么办?
  • 拥有两个同名的元素只会回发最后一个启用的输入/选择,而不是双重的。此外,只有selected 值被回发,而不是整个列表。因此,您的 hidden 位于您的 select 之前并保存选定的值。如果选择被禁用为“只读”,则回发将仅包含隐藏输入的值。如果启用了选择,则可见的选定选项将“覆盖/替换”隐藏值,这就是将被回发的值。
  • 虽然这是显而易见的解决方案,但它作为一个解决方案很糟糕,因为您必须添加另一个输入字段。
【解决方案3】:

除了当前选择的选项之外,您可以禁用所有选项,而不是选择本身。这给出了一个工作下拉列表的外观,但只有您想要传入的选项才是有效的选择。

【讨论】:

  • 理论上是个好主意——但在 IE8 之前的 IE 中不支持禁用选项。 tinyurl.com/yle4bto
【解决方案4】:
<select id="countries" onfocus="this.defaultIndex=this.selectedIndex;" onchange="this.selectedIndex=this.defaultIndex;">
<option value="1">Country1</option>
<option value="2">Country2</option>
<option value="3">Country3</option>
<option value="4">Country4</option>
<option value="5">Country5</option>
<option value="6">Country6</option>
<option value="7" selected="selected">Country7</option>
<option value="8">Country8</option>
<option value="9">Country9</option>
</select>

在 IE 6、7 和 8b2、Firefox 2 和 3、Opera 9.62、Safari 3.2.1 for Windows 和 Google Chrome 中测试和工作。

【讨论】:

  • 这样做的问题是下拉菜单呈现为好像它不是只读的。用户会认为这东西行不通……
  • 这会让用户感到困惑,因为他们仍然可以选择一个选项,但是当他们选择它时,列表会变回之前选择的值。禁用列表以防止用户选择任何内容更加直观。
  • 我有一个类似的问题并解决了它只显示选定的选项。无需 JS,减少用户的困惑...&lt;select id="countries"&gt; &lt;option value="7" selected="selected"&gt;Country7&lt;/option&gt; &lt;/select&gt;
  • @ppumkin @dana @LukasEder 不。如果你能修复这个用户体验,那就不行。例如,您可以执行onchange = 'this.selectedIndex=this.defaultIndex; alert("You should not change this..");' 之类的操作,而不仅仅是静默更改所选索引。
  • @LukasEder 对于任何对受访者体验持怀疑态度的人,他们可以添加一些 CSS 来真正强调不应更改下拉菜单。将光标设置为not-allowed,将背景颜色设置为#CCC
【解决方案5】:

如果选择下拉菜单自出生以来是只读的并且根本不需要更改,也许您应该使用另一个控件来代替?比如简单的&lt;div&gt;(加上隐藏的表单域)或&lt;input type="text"&gt;

补充:如果下拉菜单不是一直只读的并且使用 JavaScript 来启用/禁用它,那么这仍然是一个解决方案 - 只需即时修改 DOM。

【讨论】:

  • 从一开始就不是只读的。我使用 JavaScript 进行更改和更新。如果上一个下拉列表具有特定值,则此下拉列表将变为只读。
  • 那么也许您可以使用即时文本框替换此下拉菜单?
  • 是的,但在我看来,总是隐藏的输入更优雅
【解决方案6】:

遵循格兰特瓦格纳的建议;这是一个 jQuery sn-p,它使用处理函数而不是直接 onXXX 属性:

var readonlySelect = function(selector, makeReadonly) {

    $(selector).filter("select").each(function(i){
        var select = $(this);

        //remove any existing readonly handler
        if(this.readonlyFn) select.unbind("change", this.readonlyFn);
        if(this.readonlyIndex) this.readonlyIndex = null;

        if(makeReadonly) {
            this.readonlyIndex = this.selectedIndex;
            this.readonlyFn = function(){
                this.selectedIndex = this.readonlyIndex;
            };
            select.bind("change", this.readonlyFn);
        }
    });

};

【讨论】:

    【解决方案7】:

    在您计划将其设置为只读时将其设置为禁用,然后在提交表单之前删除禁用属性。

    // global variable to store original event/handler for save button
    var form_save_button_func = null;
    
    // function to get jQuery object for save button
    function get_form_button_by_id(button_id) {
        return jQuery("input[type=button]#"+button_id);
    }
    
    // alter value of disabled element
    function set_disabled_elem_value(elem_id, value)  {
        jQuery("#"+elem_id).removeAttr("disabled");
        jQuery("#"+elem_id).val(value);
        jQuery("#"+elem_id).attr('disabled','disabled');
    }
    
    function set_form_bottom_button_save_custom_code_generic(msg) {
        // save original event/handler that was either declared
        // through javascript or html onclick attribute
        // in a global variable
        form_save_button_func = get_form_button_by_id('BtnSave').prop('onclick'); // jQuery 1.6
        //form_save_button_func = get_form_button_by_id('BtnSave').prop('onclick'); // jQuery 1.7
    
        // unbind original event/handler (can use any of following statements below)
        get_form_button_by_value('BtnSave').unbind('click');
        get_form_button_by_value('BtnSave').removeAttr('onclick');
    
        // alternate save code which also calls original event/handler stored in global variable
        get_form_button_by_value('BtnSave').click(function(event){
            event.preventDefault();
            var confirm_result = confirm(msg);
            if (confirm_result) {
                if (jQuery("form.anyForm").find('input[type=text], textarea, select').filter(".disabled-form-elem").length > 0) {
                    jQuery("form.anyForm").find('input[type=text], textarea, select').filter(".disabled-form-elem").removeAttr("disabled");
                }
    
                // disallow further editing of fields once save operation is underway
                // by making them readonly
                // you can also disallow form editing by showing a large transparent
                // div over form such as loading animation with "Saving" message text
                jQuery("form.anyForm").find('input[type=text], textarea, select').attr('ReadOnly','True');
    
                // now execute original event/handler
                form_save_button_func();
            }
        });
    }
    
    $(document).ready(function() {
        // if you want to define save button code in javascript then define it now
    
        // code below for record update
        set_form_bottom_button_save_custom_code_generic("Do you really want to update this record?");
        // code below for new record
        //set_form_bottom_button_save_custom_code_generic("Do you really want to create this new record?");
    
        // start disabling elements on form load by also adding a class to identify disabled elements
        jQuery("input[type=text]#phone").addClass('disabled-form-elem').attr('disabled','disabled');
        jQuery("input[type=text]#fax").addClass('disabled-form-elem').attr('disabled','disabled');
        jQuery("select#country").addClass('disabled-form-elem').attr('disabled','disabled');
        jQuery("textarea#address").addClass('disabled-form-elem').attr('disabled','disabled');
    
        set_disabled_elem_value('phone', '123121231');
        set_disabled_elem_value('fax', '123123123');
        set_disabled_elem_value('country', 'Pakistan');
        set_disabled_elem_value('address', 'address');
    
    }); // end of $(document).ready function
    

    【讨论】:

    • 这听起来像是等待发生的竞争条件。
    【解决方案8】:

    我用 jquery 解决了:

          $("select.myselect").bind("focus", function(){
            if($(this).hasClass('readonly'))
            {
              $(this).blur();   
              return;
            }
          });
    

    【讨论】:

    • 效果很好,尽管鼠标悬停动画仍会显示一个看起来可点击的下拉箭头。
    • 这在 Chrome 26 中对我不起作用:选择仍然功能齐全。
    • 但是在 IE 上双击它仍然显示列表。无论如何要防止这种情况发生?
    【解决方案9】:

    以下对我有用:

    $('select[name=country]').attr("disabled", "disabled"); 
    

    【讨论】:

    • 仅供参考:禁用的表单字段不会包含在提交中。
    【解决方案10】:

    html解决方案:

    &lt;select onfocus="this.blur();"&gt;

    javascript 的:

    selectElement.addEventListener("focus", selectElement.blur, true); selectElement.attachEvent("focus", selectElement.blur); //thanks, IE

    删除:

    selectElement.removeEventListener("focus", selectElement.blur, true); selectElement.detachEvent("focus", selectElement.blur); //thanks, IE

    编辑:添加删除方法

    【讨论】:

    • @ButtleButkus javascript 的工作吗?我想这可能是与浏览器相关的问题。您是否尝试将 tabindex 添加到元素
    • HTML 解决方案不适用于当今的 Chrome。 :-(
    【解决方案11】:

    我通过隐藏选择框并在其位置显示span 来管理它,仅具有信息价值。在禁用.readonly 类的情况下,我们还需要删除.toVanish 元素并显示.toShow 元素。

     $( '.readonly' ).live( 'focus', function(e) {
                    $( this ).attr( 'readonly', 'readonly' )
                    if( $( this ).get(0).tagName == 'SELECT' ) {
                        $( this ).before( '<span class="toVanish readonly" style="border:1px solid; padding:5px">' 
                                + $( this ).find( 'option:selected' ).html() + '</span>' )
                        $( this ).addClass( 'toShow' )
                        $( this ).hide()
                }
        });
    

    【讨论】:

      【解决方案12】:

      在 IE 中,我能够通过双击来击败 o​​nfocus=>onblur 方法。 但是记住这个值,然后在 onchange 事件中恢复它似乎可以解决这个问题。

      <select onfocus="this.oldvalue=this.value;this.blur();" onchange="this.value=this.oldvalue;">
      ....
      </select>
      

      您可以使用 javascript 变量在没有扩展属性的情况下执行类似操作。

      【讨论】:

        【解决方案13】:

        另一个更现代的选项(不是双关语)是禁用选择元素的所有选项,而不是所选元素。

        但是请注意,这是一个 HTML 4.0 功能 即 6,7,8 beta 1 似乎不尊重这一点。

        http://www.gtalbot.org/BrowserBugsSection/MSIE7Bugs/OptionDisabledSupport.html

        【讨论】:

          【解决方案14】:

          简单的jQuery解决方案

          如果您的选择有 readonly 类,请使用它

          jQuery('select.readonly option:not(:selected)').attr('disabled',true);
          

          或者如果你的选择有readonly="readonly" 属性

          $('select[readonly="readonly"] option:not(:selected)').attr('disabled',true);
          

          【讨论】:

          • 请稍微解释一下您的代码。我们是否必须向选择元素添加一个“只读”类?我们何时必须调用此代码:仅在 document.ready 中或每次启用/禁用选择时?你的代码 noscript 安全吗?
          • $(document).ready(function(){$('select option:not(:selected)').attr('disabled',true);}); 在单选上工作得很好。不需要“只读”类。多选是有问题的,因为如果已经选择了多个选项并因此未禁用,并且用户选择了未禁用的选项之一,则其他先前选择的选项将变为未选中。
          • 什么都不懂。
          • 它会为“只读”类的选择框禁用选定选项以外的选项。如果你手头有选择元素,你可以写:$select.find('option').not(':selected').attr('disabled', 'disabled');
          • 我喜欢这个解决方案。我会将选择器更改为select[readonly],这样您只需将 readonly 属性添加到元素 - 这样您就不必将选择与任何其他类型区别对待。然后javascript逐渐增强效果。请记住,此解决方案(以及其他大多数解决方案)仅帮助用户代理提供最佳用户体验 - 它实际上并没有强制执行任何操作(如果需要,必须在服务器端完成)。
          【解决方案15】:

          这里尝试使用自定义的 jQuery 函数来实现功能(这里提到过):

          $(function(){
          
           $.prototype.toggleDisable = function(flag) {
              // prepare some values
              var selectId = $(this).attr('id');
              var hiddenId = selectId + 'hidden';
              if (flag) {
                // disable the select - however this will not submit the value of the select
                // a new hidden form element will be created below to compensate for the 
                // non-submitted select value 
                $(this).attr('disabled', true);
          
                // gather attributes
                var selectVal = $(this).val();
                var selectName = $(this).attr('name');
          
                // creates a hidden form element to submit the value of the disabled select
                $(this).parents('form').append($('<input></input>').
                  attr('type', 'hidden').
                  attr('id', hiddenId).
                  attr('name', selectName).
                  val(selectVal) );
              } else {
                // remove the newly-created hidden form element
                $(this).parents('form').remove(hiddenId);
                // enable back the element
                $(this).removeAttr('disabled');
              }
            }
          
            // Usage
            // $('#some_select_element').toggleDisable(true);
            // $('#some_select_element').toggleDisable(false);
          
          });
          

          【讨论】:

            【解决方案16】:

            如果你使用jquery validate,你可以执行以下操作,我使用disabled属性没有问题:

            $(function(){
                $('#myform').validate({
                    submitHandler:function(form){
                        $('select').removeAttr('disabled');
                        form.submit();
                    }
                });
            });
            

            【讨论】:

              【解决方案17】:

              一种简单的服务器端方法是删除除您要选择的选项之外的所有选项。因此,在 Zend Framework 1.12 中,如果 $element 是 Zend_Form_Element_Select:

               $value =  $element->getValue();
               $options = $element->getAttrib('options');
               $sole_option = array($value => $options[$value]);
               $element->setAttrib('options', $sole_option);
              

              【讨论】:

                【解决方案18】:

                在选项中,您可以使用disabled="disabled",而不是选择本身

                【讨论】:

                • 为什么这被否决了?这是一个完全合理的答案。如果禁用所有选择框选项,则选择框实际上是只读的。
                • 先阅读问题...有“唯一的问题是禁用的 HTML 表单输入不会包含在 POST / GET 数据中。”
                • 在这里建议的答案中,option 被禁用,而不是选择;因此数据仍然被发送,因此它是有效的……
                【解决方案19】:

                除了禁用不应该选择的选项之外,我还想让它们从列表中消失,但如果我以后需要的话,仍然可以启用它们:

                $("select[readonly]").find("option:not(:selected)").hide().attr("disabled",true);
                

                这会找到所有具有 readonly 属性的 select 元素,然后在那些未选中的 select 中找到所有选项,然后隐藏它们并禁用它们。

                出于性能原因将jquery查询分开2很重要,因为jquery从右到左读取它们,代码:

                $("select[readonly] option:not(:selected)")
                

                将首先在文档中查找所有未选择的选项,然后使用只读属性过滤选择中的选项。

                【讨论】:

                • 也许是.prop("disabled", true)
                【解决方案20】:

                只需在提交表单之前删除 disabled 属性。

                    $('form').submit(function () {
                        $("#Id_Unidade").attr("disabled", false);
                    });
                

                【讨论】:

                  【解决方案21】:

                  遇到同样的问题,发现表单的非常有用的属性 - submitdisabledcontrols

                  将其设置为 True 并且禁用的输入现在是 POST

                  【讨论】:

                  • 这不是表单的标准属性。它仅适用于 ASP.NET。
                  【解决方案22】:
                  var selectedOpt;//初始化var var newIdForHidden;//初始化var $('.disabledOnEdit').focusin(function(){ selectedOpt = $(this).find(":selected").val(); newIdForHidden = $(this).attr('id')+'Hidden'; //alert(selectedOpt+','+newIdForHidden); $(this).append(''); $(this).find('input.hiddenSelectedOpt').attr('id',newIdForHidden).val(selectedOpt); }); $('.disabledOnEdit').focusout(function(){ var oldSelectedValue=$(this).find('input.hiddenSelectedOpt').val(); $(this).val(oldSelectedValue); });

                  【讨论】:

                    【解决方案23】:

                    如果您禁用表单字段,则在提交表单时不会发送该字段。 因此,如果您需要像 disabled 一样工作但发送值的 readonly,请执行以下操作:

                    在元素的只读属性发生任何变化之后。

                    $('select.readonly option:not(:selected)').attr('disabled',true);
                    
                    $('select:not([readonly]) option').removeAttr('disabled');
                    

                    【讨论】:

                      【解决方案24】:

                      我们还可以禁用除所选选项之外的所有选项。

                      这样下拉菜单仍然有效(并提交其值),但用户无法选择其他值。

                      Demo

                      <select>
                          <option disabled>1</option>
                          <option selected>2</option>
                          <option disabled>3</option>
                      </select>

                      【讨论】:

                      • 不错的动态选项
                      • 非常适合单值 SELECT 标记!但不适用于
                      • Browser support 用于option 标签的disabled 属性
                      • 这是一个很好的解决方案。我要补充一点,你可以像这样使用 jQuery 轻松实现它:$("#yourSelectId option:not(:selected)).attr("disabled", "disabled")
                      • $('#yourSelectId option:not(:selected)').attr('disabled', 'disabled')
                      【解决方案25】:

                      简单的 CSS 解决方案:

                      select[readonly]{
                          background: #eee;
                          cursor:no-drop;
                      }
                      
                      select[readonly] option{
                          display:none;
                      }
                      

                      这会导致 Select 变为灰色,并在悬停时显示漂亮的“禁用”光标
                      并且在选择选项列表时为“空”,因此您无法更改其值。

                      【讨论】:

                      • 如果你有一个 CSRF 验证(比如在 symfony 和许多其他框架中),它不会起作用。
                      【解决方案26】:

                      select 元素添加readOnly 属性的另一种方法是使用css

                      你可以这样做:

                      $('#selection').css('pointer-events','none');
                      

                      DEMO

                      【讨论】:

                      • 不错的解决方案。但是您仍然可以使用键盘更改值。
                      • 是的,这太棒了。要使用键盘更改值,您必须 TAB 到元素,然后它会被选中。如果您将背景颜色设为灰色或禁用,您还会在视觉上通知用户这是“禁用”,而实际上它并未禁用。没有人支持 IE 了,所以谁在乎。如果你想阻止,你也可以设置一个 keydown 阻止默认值。
                      • 很不正统!!如果选择需要阻止页面渲染,... .on('mouseover', function(){ ... });
                      • pointer-events: none 防止鼠标光标聚焦。为了防止键盘聚焦,您可以通过在所有聚焦事件上立即模糊来补充它:$('select').css('pointer-events', 'none').on('focus', function () {$(this).blur();});
                      【解决方案27】:

                      这是我找到的最佳解决方案:

                      $("#YourSELECTIdHere option:not(:selected)").prop("disabled", true);
                      

                      上面的代码禁用所有其他未选中的选项,同时保持选中的选项处于启用状态。这样做所选选项将使其成为回发数据。

                      【讨论】:

                        【解决方案28】:

                        select multiple 对上述代码建议的响应几乎没有。经过大量的大锤和拼凑,我最终得到了这个:

                        var thisId="";
                        var thisVal="";
                        function selectAll(){
                            $("#"+thisId+" option").each(function(){
                                if(!$(this).prop("disabled"))$(this).prop("selected",true);
                            });
                            $("#"+thisId).prop("disabled",false);
                        }
                        $(document).ready(function(){
                            $("select option:not(:selected)").attr('disabled',true);
                            $("select[multiple]").focus(function(){
                                thisId=$(this).prop("id");
                                thisVal=$(this).val();
                                $(this).prop("disabled",true).blur();
                                setTimeout("selectAll();",200);
                            });
                        });
                        

                        【讨论】:

                          【解决方案29】:

                          这是最简单也是最好的解决方案。 您将在您的选择上设置一个 readolny 属性,或任何其他属性,如 data-readonly,并执行以下操作

                          $("select[readonly]").live("focus mousedown mouseup click",function(e){
                              e.preventDefault();
                              e.stopPropagation();
                          });
                          

                          【讨论】:

                          • 您应该在此处添加 keyup 广告 keydown 以及下拉菜单仍然可以通过“tabbing”进入它并使用箭头键更改值。
                          【解决方案30】:

                          非常简单。首先将值存储在变量中。然后将事件设置值更改为保存初始值的存储变量

                          我有一个名字叫映射。那么我的代码如下;

                          $("document").ready(function(){ 
                              var mapping=$("select[name=mapping]").val();
                              $("select[name=mapping]").change(function(){
                                  $("select[name=mapping]").val(mapping);
                              });
                          });
                          

                          【讨论】:

                            猜你喜欢
                            • 2016-01-26
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2011-12-16
                            • 2022-06-15
                            • 1970-01-01
                            相关资源
                            最近更新 更多