超文本标记语言表单只读SELECT标记/输入

根据超文本标记语言规范,超文本标记语言中的select标签没有readonly属性,只有disabled属性。所以如果你想阻止用户更改下拉列表,你必须使用disabled

唯一的问题是禁用的超文本标记语言表单输入不包含在POST/GET数据中。

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

925163 次浏览

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

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

jQuery示例:

  • 要禁用它:

    $('#yourSelect').prop('disabled', true);
    
  • To re-enable it before submission so that GET / POST data is included:

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

In addition, you could re-enable every disabled input or select:

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

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

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

下面是一个demo:

$('#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>

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

<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,Safari3.2.1 Windows和GoogleChrome。

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

添加:如果下拉列表不是一直都是只读的,并且使用JavaScript来启用/禁用它,那么这仍然是一个解决方案-只需动态修改DOM。

遵循Grant Wagner的建议;这是一个jQuery片段,它使用处理程序函数而不是直接使用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);
}
});


};

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

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

我用jQuery解决了它:

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

下面为我工作:

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

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

编辑:添加删除方法

我通过隐藏选择框并在其位置显示一个只有信息值的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()
}
});

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

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

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

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

请注意,这是一个超文本标记语言4.0功能 而IE 6,7,8 beta 1似乎不尊重这一点。

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

简单的jQuery解决方案

如果您的选择具有readonly类,请使用此选项

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

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

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

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


});

如果您使用的是jQuery验证,您可以执行以下操作,我使用禁用属性没有问题:

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

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

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

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

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

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

这将查找具有只读属性的所有选择元素,然后查找未选中的选择中的所有选项,然后隐藏它们并禁用它们。

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

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

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

简单地说,在提交表单之前删除禁用属性。

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

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

将其设置为True,禁用的输入现在为POST

var selectedOpt;//initialize var
var newIdForHidden;//initialize 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);
});

如果禁用表单字段,表单提交时不会发送。 所以如果你需要一个像disabled一样工作的readonly,但发送值是这样做的:

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

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


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

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

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

演示

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

简单的CSS解决方案:

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


select[readonly] option{
display:none;
}

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

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

你可以这样做:

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

演示

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

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

上面的代码禁用在保持所选选项启用的同时未选择所有其他选项。这样做所选选项将使其进入回发数据。

选择多个对上述代码建议的响应几乎没有那么好。通过大量的大锤和拼凑,我最终得到了这个:

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

这是最好的解决方案。 您将在选择上设置readolny attr,或任何其他attr,如data-readOnly,并执行以下操作

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

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

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

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

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

如果您的选择标记应该是只读的,那么从逻辑上讲,您必须将选择框转换为单个“文本”字段。

我说逻辑上,因为它就像: "我必须向用户显示一个值"

无论值是否来自选择标记,仍然是单个值,无法更改(只读)。

因此,从逻辑上讲,只有在首次插入值时才使用选择标记。

然后,当你需要显示这个值时,你必须把它放在“文本字段只读”上。

如果只读,则成为值列表(所选值)的多重选择也是如此

我使用“text”是因为只读标记不需要“type”属性。 干杯

我知道这已经太晚了,但它可以用简单的CSS完成:

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

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

不需要JavaScript黑客。

我发现用普通的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>

这样,没有可见的效果变化,这将在<FORM>中发布/获取。

更简单: 将style属性添加到您的选择标签:

style="pointer-events: none;"

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

简单地使用一个禁用类。

css:

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

js:

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

超文本标记语言:

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

我知道这不会帮助每个人(如果你只是客户端),但会帮助一些全栈并控制后端和前端的人。

如果用户没有编辑字段的权限,我只返回下拉列表的当前选择。

这是我的一些后端控制器:

        #region Prepare Action Priviledges
editAuditVM.ExtAuditEditRoleMatrixVM = new ExtAuditEditRoleMatrixVM
{
CanEditAcn = _extAuditEditRoleMatrixHelper.CanEditAcn(user, audit),
CanEditSensitiveDesignation = _extAuditEditRoleMatrixHelper.CanEditSensitiveDesignation(user, audit),
CanEditTitle = _extAuditEditRoleMatrixHelper.CanEditTitle(),
CanEditAuditScope = _extAuditEditRoleMatrixHelper.CanEditAuditScope(user, audit)
};
#endregion




#region Prepare SelectLists for Drop Downs
#region AuditScope List
IQueryable<SelectListItem> auditScopes = _auditTypesRepo.AuditTypes
.Where(at => at.AuditTypeClassCode.ToLower() == "e")
.Select(at => new SelectListItem
{ Text = at.AuditTypeText, Value = at.AuditTypeID.ToString() });
// Cannot make a select readonly on client side.
//  So only return currently selected option.
if (!editAuditVM.ExtAuditEditRoleMatrixVM.CanEditAuditScope)
{
auditScopes = auditScopes
.Where(ascopeId => ascopeId.Value == editAuditVM.ExternalAudit.AuditTypeID.ToString());
}
#endregion
#endregion

模拟选择的只读属性的最佳方法是什么 标签,仍然得到POST数据?

只需将其设为输入/文本字段并向其添加“只读”属性。如果选择实际上是“禁用”的,那么您无论如何都无法更改值,因此您不需要选择标记,您可以简单地将“选定”值显示为只读文本输入。对于大多数UI目的,我认为这应该就足够了。

所以不管出于什么原因,这里提到的所有基于jQuery的解决方案都不适合我。所以这里有一个纯javascript解决方案,它在执行POST时也应该保留选定的值。

setDropdownReadOnly('yourIdGoesHere',true/false)
    function setDropdownReadOnly(controlName, state) {
var ddl = document.getElementById(controlName);


for (i = 0; i < ddl.length; i++) {
if (i == ddl.selectedIndex)
ddl[i].disabled = false;
else
ddl[i].disabled = state;
}
}

派对有点晚了但这对我来说似乎很完美

select[readonly] {
pointer-events:none;
}

我的解决方案是按照这里许多人的建议添加select[readonly] { pointer-events: none; }样式,然后添加这个JS来处理键盘事件:

$(document).on('keydown', 'select[readonly]', function(e) {
if (e.keyCode != 9) {
if (e.preventDefault) {
e.preventDefault();
}


e.returnValue = false;
e.cancel = true;
}
});

这仍然允许使用tab遍历元素。

input是你的<select>元素:

input.querySelectorAll(':not([selected])').forEach(option => {
option.disabled = true
})

这将保留数据中的选择(因为它没有被禁用),只有未被选中的option被禁用,因此不可选择。 结果是一个可读的选择,不能更改(=>只读)。

摘自https://stackoverflow.com/a/71086058/18183749

如果您不能使用“禁用”attribut(因为它会擦除值的值 输入在POST),并注意到html attribut'readOnly'只工作 关于文本区域和一些输入(文本、密码、搜索,据我所知), 最后,如果你不想费心复制你所有的 选择,复选框和单选隐藏的输入逻辑,你可能会发现 下面的函数或任何你喜欢的内部逻辑:

addReadOnlyToFormElements = function (idElement) {
    

// html readonly don't work on input of type checkbox and radio, neither on select. So, a safe trick is to disable the non-selected items
$('#' + idElement + ' select>option:not([selected])').prop('disabled',true);
    

// and, on the selected ones, to mimic readOnly appearance
$('#' + idElement + ' select').css('background-color','#eee');
}

没有什么比删除这些只读更容易的了

removeReadOnlyFromFormElements = function (idElement) {


// Remove the disabled attribut on non-selected
$('#' + idElement + ' select>option:not([selected])').prop('disabled',false);


// Remove readOnly appearance on selected ones
$('#' + idElement + ' select').css('background-color','');
}

这可能与其他解决方案类似,但简化为更少的行。

假设有一个jQuery函数禁用目标选项…

$("select[id='country']").val('PH').attr("disabled", true);
$("select[id='country']").parent().append("<input type='hidden' id='country' value='PH'>");

如果您想重新启用该选项…

$("select[id='country']").attr("disabled", false);
$("input[id='country']").remove();

这个JavaScript找到所有带有只读属性的“选择”,然后将禁用放在“选项”中,除了选定的(用于回发)

document.querySelectorAll("select[readonly] > option:not([selected])").forEach( (el) => el.setAttribute("disabled", "disabled") );
without readonly: <select>
<option>1</option>
<option selected>2</option>
<option>3</option>
</select>


<br>
with readonly: <select readonly="readonly">
<option>1</option>
<option selected>2</option>
<option>3</option>
</select>

[简单的解决方案]

由于OP特别要求他不想禁用选择元素,以下是我用来使选择只读的

在html

<select style="pointer-events: none;" onclick="return false;" onkeydown="return false;" ></select>

就这样了

或者如果你想通过JavaScript来实现

let isReadOnly = true ;


selectElement.onclick = function () {
return !isReadOnly ;
};
selectElement.onkeydown =function(){
return !isReadOnly ;
} ;
selectElement.style.pointerEvents = isReadOnly ? "none" : "all" ;

补充说明

  • 将指针事件设置为无会禁用使用鼠标/光标事件编辑“选择元素”
  • 将onClick&onkeydown函数设置为返回false会禁用使用键盘编辑“selt-元素”

这样,您就不必创建任何额外的元素,或者使用javascript禁用/重新启用元素,或者搞乱表单提交逻辑,或者使用任何第三方库。

另外,您可以轻松添加css样式,例如将backgrouns-Color设置为灰色或将文本颜色设置为灰色以暗示元素是只读的。我还没有将其添加到代码中,因为这对您的站点主题非常特定