HTML表单只读SELECT标记/输入


587

根据HTML规范,selectHTML中的标记没有readonly属性,只有disabled属性。因此,如果要阻止用户更改下拉菜单,则必须使用disabled

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

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


5
不要在服务器端依赖它。任何人都可以创建自己的HTML页面并将其设为RW。
布伦丹·伯德

11
但这不是特定于PHP的问题。
Kaleb Brasee 2013年

4
我建议在这种情况下完全不使用select元素。有什么原因不能只将值显示为纯文本?
Big McLargeHuge 2014年

2
@ppumkin您的评论没有任何意义。我并不是说对于选择或隐藏的表单域永远没有很好的用例。OP在页面上显示文本时遇到麻烦,我只是想知道在这种情况下使用select元素的目的是什么。
Big McLargeHuge 2014年

2
我一定读错了问题。他说他想禁用选择,以便用户不要更改它。也许他需要使用selects呈现页面并使用jquery来防止更改。但是当他将其提交回来时,没有任何数据。我也一样 我需要显示由其他选择过滤的选择,最后一个下拉列表通过ajax保存到DB,因此所有先前的列表都必须锁定。是的,当我重新呈现页面时,好吧,我可以显示标签而不是选择内容。但这不是问题:)
Piotr Kula

Answers:


461

您应该保留该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>


5
如果要重新启用选择,那么当然还必须禁用或删除隐藏的输入(在复制其值后,如所述)。否则,您将获得双倍提交的值
亚当(Adam)

1
@max啊!好的,那也可以。自从您说隐藏的输入应该具有与选择具有名称的“相同名称”一样,我一直认为。
亚当

2
如果我使用的是多重选择怎么办?
Anyul Rivas

2
具有两个具有相同名称的元素将仅回发最后启用的输入/选定的内容,而不是双重的。同样,只有selected值被回发而不是整个列表。因此,您hidden坐在您的前面,select并保持选定的值。如果选择被禁用为“只读”,则回发将仅包含隐藏输入的值。如果启用了选择,则可见的选定选项将“覆盖/替换”隐藏的值,该值将被回发。
Piotr Kula 2014年

29
虽然这是显而易见的解决方案,但它很烂,因为您必须添加另一个输入字段。
Donato

189

我们也可以用这个

禁用除所选选项之外的所有选项:

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

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

演示版


3
动态选项的好选择
Diego Favero 2015年

10
非常适合单值SELECT标记!但是对于<select multiple>无效,它仍然允许用户取消选择某些选定选项,从而更改值。
米哈伊尔·邦金

2
浏览器option标签disabled属性的支持
Jo。

4
这是一个很好的解决方案。我要补充一点,您可以使用jQuery这样轻松地实现它: $("#yourSelectId option:not(:selected)).attr("disabled", "disabled")
Onkel-j,

105

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

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

jQuery示例:

  • 禁用它:

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

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

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

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

4
使用.prop('disabled',true / false)设置disabled属性。该属性不会更改实际状态。
巴黎Char

我认为此解决方案比@bezmax解决方案聪明。因为如果添加隐藏的输入,我们必须考虑到在任何时候都仅启用每个输入(名称相同)之一。否则,如果同时启用了两个输入,则在服务器端,程序将采用可能导致异常的输入数组(例如,如果我们不处理这种情况,并且我们期望一个字符串并使用'Request.Form [FieldName] '命令)
MiT 2015年

@Kevin,工作案例> 90%。另外,您必须要有jquery。
sitilge '16

这是更清洁的公认答案。如果您不想再禁用元素并且没有额外的输入标签,则更容易撤消逻辑。
Haohmaru

51

readOnlyselect元素进行属性处理的另一种方法是使用css

你可以这样做:

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

演示


8
不错的解决方案。但是您仍然可以使用键盘更改该值。
Mario Werner 2014年

1
是的,这真棒。要使用键盘更改值,您必须将TAB移至该元素,然后该元素将被选中。如果将背景色设置为灰色或禁用,则还可以在视觉上通知用户该功能实际上未被禁用时被“禁用”。没人再支持IE,所以谁在乎。如果您想阻止,也可以将keydown阻止设置为默认值。
Piotr Kula 2014年

相当非正统!如果需要阻止所选内容呈现页面,... .on('mouseover', function(){ ... });
Fr0zenFyr 2015年

pointer-events: none防止鼠标光标聚焦。为了防止键盘产生焦点,您可以通过在所有焦点事件上立即模糊来进行补充:$('select').css('pointer-events', 'none').on('focus', function () {$(this).blur();});
Quinn Comendant

39
<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(适用于Windows)和Google Chrome浏览器中工作。


15
这样做的问题是,下拉列表的呈现方式好像不是只读的。用户会认为这不起作用...
Lukas Eder

8
这使用户感到困惑,因为他们仍然可以选择一个选项,但是当他们选择它时,列表将变回先前选择的值。禁用列表以防止用户完全选择任何东西,这更加直观。
dana 2012年

11
我有一个类似的问题,解决了它只显示选定的选项。无需JS,为用户减少了混乱…… <select id="countries"> <option value="7" selected="selected">Country7</option> </select>
Potherca

1
@ppumkin @dana @LukasEder号。如果您可以修复此UX,则不行。例如,您可以做类似的事情,onchange = 'this.selectedIndex=this.defaultIndex; alert("You should not change this..");'而不是仅默默地更改选定的索引。
Fr0zenFyr 2015年

1
@LukasEder对于任何对受访者体验持怀疑态度的人,他们可以添加一些CSS来真正强调下拉列表不应更改。将光标设置为not-allowed,将背景色设置为#CCC
亚历山大·迪克森

36

简单的jQuery解决方案

如果您选择的readonly课程是此类,请使用此选项

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

或者,如果您选择的内容具有此readonly="readonly"属性

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

7
请稍微解释一下您的代码。我们是否必须在选择元素中添加“只读”类?我们什么时候必须调用此代码:仅在document.ready中或每次启用/禁用选择时?您的代码noscript安全吗?
anar khalilov 2014年

$(document).ready(function(){$('select option:not(:selected)').attr('disabled',true);});单选工作正常。不需要“只读”类。多选是有问题的,因为如果已经选择了多个选项,因此没有被禁用,并且用户选择了一个未被禁用的选项,则其他先前选择的选项将变为未选择状态。
戈登2014年

什么都不懂
Piotr Kula 2014年

对于具有“只读”类的选择框,它将禁用除所选选项之外的其他选项。如果您有选择元素,则可以编写:$select.find('option').not(':selected').attr('disabled', 'disabled');
Semra 2015年

1
我喜欢这个解决方案。我将选择器更改为,select[readonly]以便您只需将readonly属性添加到元素-这样,您不必将选择与其他任何类型区别对待。然后,javascript会逐渐增强效果。请记住,此解决方案(以及其他大多数解决方案)仅有助于用户代理提供最佳的用户体验-它实际上并没有执行任何操作(如果需要,必须在服务器端完成)。
jgivoni 2015年

21

简单的CSS解决方案:

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

select[readonly] option{
    display:none;
}

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


1
如果您有CSRF验证(例如在symfony和许多其他框架中),它将无法正常工作。
ThEBiShOp '02


11

这是我发现的最佳解决方案:

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

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


11

我知道这为时已晚,但是可以使用简单的CSS来完成:

select[readonly] option, select[readonly] optgroup {
    display: none;
}

当处于选中readonly状态时,样式将隐藏所有选项和组,因此用户无法更改其选择。

无需JavaScript技巧。


漂亮又简单。我喜欢。
乔纳森·父母·勒维斯克

这是一个很好的解决方案。谢谢!
OderWat

10

更简单:将style属性添加到您的select标签中:

style="pointer-events: none;"

它对我有用,但是指针事件将使跨浏览器支持吗?
Abhijit Jagtap '17

3
它不会工作。用户可以使用键盘更改输入。
Sandhu,

6

这是最简单,最好的解决方案。您将在选择的内容上设置一个readolny属性,或将其设置为data-readonly之类的其他属性,然后执行以下操作

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

1
您应该在此处添加keyup广告keydown以及下拉菜单中仍然可用的下拉菜单,然后使用箭头键更改该值。
apfz

5

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

// 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

这听起来像是在等待比赛条件的发生。
布伦丹·伯德

5

除了禁用不应选择的选项外,我还想使它们从列表中消失,但是如果以后需要,仍能够启用它们:

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

这将找到具有只读属性的所有选择元素,然后在那些未选择的选择内找到所有选项,然后将其隐藏并禁用它们。

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

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

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


也许.prop("disabled", true)改为
萨姆(Sam)2014年

4

一种简单的服务器端方法是删除所有要选择的选项之外的选项。因此,在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);

4

如果您禁用表单字段,则在提交表单时将不会发送该字段。因此,如果您需要一个readonly类似于disabled但发送值的文件,请执行以下操作:

元素的只读属性发生任何更改后。

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

$('select:not([readonly]) option').removeAttr('disabled');

4

tabindex解决方案。适用于选择,但也适用于文本输入。

只需使用.disabled类。

CSS:

.disabled {
    pointer-events:none; /* No cursor */
    background-color: #eee; /* Gray background */
}

JS:

$(".disabled").attr("tabindex", "-1");

HTML:

<select class="disabled">
    <option value="0">0</option>
</select>

<input type="text" class="disabled" />

编辑:使用Internet Explorer,您还需要以下JS:

$(document).on("mousedown", ".disabled", function (e) {
    e.preventDefault();
});

2

遵循Grant Wagners的建议;这是一个使用处理程序函数(而不是直接的onXXX属性)执行的jQuery代码段:

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);
        }
    });

};

2

我用jQuery解决了它:

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

尽管鼠标悬停动画仍会显示一个看起来可单击的下拉箭头,但效果很好。
Johncl 2011年

在Chrome 26中,这不适用于我:选择仍然可以正常使用。
安迪

但是当您在IE上双击它时,它仍然显示该列表。无论如何要防止这种情况?
2013年

2

如果您正在使用jquery validate,则可以执行以下操作,我使用了disable属性没有问题:

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

2

我发现使用普通的javascript(即无需JQuery库)的效果很好,是将<select>标记的innerHTML更改为所需的单个剩余值。

之前:

<select name='day' id='day'>
  <option>SUN</option>
  <option>MON</option>
  <option>TUE</option>
  <option>WED</option>
  <option>THU</option>
  <option>FRI</option>
  <option>SAT</option>
</select>

示例Javascript:

document.getElementById('day').innerHTML = '<option>FRI</option>';

后:

<select name='day' id='day'>
  <option>FRI</option>
</select>

这样,视觉效果不会改变,这将在内进行POST / GET <FORM>


1

除了当前选择的选项之外,您还可以禁用所有选项,而不是选择本身。这样会显示一个有效的下拉菜单,但是只有要传递的选项才是有效的选择。


3
从理论上讲是个好主意-但在IE8之前的IE中,不支持禁用选项。tinyurl.com/yle4bto
scunliffe

1

html解决方案:

<select onfocus="this.blur();">

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
Kadmillos 2014年

1

只需在提交表单之前删除Disabled属性即可。

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

1
<select id="case_reason" name="case_reason" disabled="disabled">

disabled="disabled" ->将从数据库中获取您的价值,并在表单中显示它。 readonly="readonly" ->您可以在选择框中更改值,但是您的值无法保存在数据库中。


错误,已保存。看起来并非所有浏览器都处理过'readonly'属性,因此该属性不可靠。
richey

0

如果选择下拉列表自出生以来是只读的,并且根本不需要更改,那么也许应该改用另一个控件?就像一个简单的<div>(加上隐藏的表单字段)还是一个<input type="text">

补充:如果下拉列表并非始终都是只读的,并且使用JavaScript启用/禁用它,那么这仍然是一种解决方案-只需即时修改DOM。


从一开始就不是只读的。我使用JavaScript进行更改和更新。如果上一个下拉列表具有特定值,则该下拉列表将变为只读。
Jrgns

然后,也许您可​​以使用文本框即时替换此下拉菜单?
Vilx-

是的,但是在我看来,始终隐藏的输入更加优雅
Jrgns

0

下面为我​​工作:

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

11
仅供参考:禁用表单字段不会包含在提交中。
mz_01 2011年

0

我通过隐藏选择框并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()
            }
    });

0

在IE中,我可以通过双击来击败onfocus => onblur方法。但是记住该值,然后在onchange事件中将其还原似乎可以解决该问题。

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

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


0

这是尝试使用自定义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);

});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.