Selon les spécifications HTML, la balise select
en HTML ne possède pas d'attribut readonly
, mais un attribut disabled
. Donc, si vous voulez empêcher l'utilisateur de changer le menu déroulant, vous devez utiliser disabled
.
Le seul problème est que les entrées de formulaire HTML désactivées ne sont pas incluses dans les données POST/GET.
Quel est le meilleur moyen d’émuler l’attribut readonly
pour une balise select
et d’obtenir les données POST?
Vous devez conserver l'élément select
disabled
mais également en ajouter une autre input
masquée de même nom et de même valeur.
Si vous réactivez votre SELECT, vous devez copier sa valeur dans l'entrée masquée d'un événement onchange et désactiver (ou supprimer) l'entrée masquée.
Voici une démo:
$('#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>
Nous pourrions aussi utiliser ceci
Désactiver tout sauf l'option sélectionnée:
<select>
<option disabled>1</option>
<option selected>2</option>
<option disabled>3</option>
</select>
De cette façon, la liste déroulante fonctionne toujours (et soumet sa valeur) mais l'utilisateur ne peut pas sélectionner une autre valeur.
Vous pouvez réactiver l'objet de sélection lors de l'envoi.
EDIT: c'est-à-dire, désactiver normalement la balise select (avec l'attribut disabled) puis la réactiver automatiquement juste avant de soumettre le formulaire:
Exemple avec jQuery:
Pour le désactiver:
$('#yourSelect').prop('disabled', true);
Pour le réactiver avant la soumission afin que les données GET/POST soient incluses:
$('#yourForm').on('submit', function() {
$('#yourSelect').prop('disabled', false);
});
En outre, vous pouvez réactiver chaque entrée désactivée ou sélectionner:
$('#yourForm').on('submit', function() {
$('input, select').prop('disabled', false);
});
une autre façon de créer un attribut readOnly
en un élément select
consiste à utiliser css
tu pourrais faire comme:
$('#selection').css('pointer-events','none');
<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>
Testé et utilisé dans IE 6, 7 et 8b2, Firefox 2 et 3, Opera 9.62, Safari 3.2.1 pour Windows et Google Chrome.
Solution jQuery simple
Utilisez ceci si vos sélections ont la classe readonly
jQuery('select.readonly option:not(:selected)').attr('disabled',true);
Ou ceci si vos sélections ont l'attribut readonly="readonly"
$('select[readonly="readonly"] option:not(:selected)').attr('disabled',true);
Solution CSS simple:
select[readonly]{
background: #eee;
cursor:no-drop;
}
select[readonly] option{
display:none;
}
Il en résulte que Select est grisé avec le curseur "désactivé" de Nice en survol
et sélectionnez la liste d’options est "vide", vous ne pouvez donc pas changer sa valeur.
Encore une autre option plus contemporaine (sans jeu de mots) consiste à désactiver toutes les options de l’élément select autres que celui sélectionné.
notez cependant qu'il s'agit d'une fonctionnalité HTML 4.0 et que 6,7,8 beta 1 semble ne pas respecter cela.
http://www.gtalbot.org/BrowserBugsSection/MSIE7Bugs/OptionDisabledSupport.html
C'est la meilleure solution que j'ai trouvée:
$("#YourSELECTIdHere option:not(:selected)").prop("disabled", true);
Le code ci-dessusdésactivetoutes les autres options non sélectionnées tout en maintenant l’option sélectionnée. Ainsi, l'option sélectionnée sera intégrée aux données de post-retour.
Plus facile quand même: Ajoutez l'attribut style à votre balise select :
style="pointer-events: none;"
Je sais que c'est beaucoup trop tard, mais cela peut se faire avec du simple CSS:
select[readonly] option, select[readonly] optgroup {
display: none;
}
Le style masque toutes les options et les groupes lorsque la sélection est à l'état readonly
, de sorte que l'utilisateur ne peut pas modifier sa sélection.
Pas de piratage JavaScript nécessaire.
Définissez la sélection désactivée lorsque vous planifiez qu'elle soit en lecture seule, puis supprimez l'attribut désactivé juste avant de soumettre le formulaire.
// 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
C’est la solution la plus simple et la meilleure… .. Vous allez définir un attr de lecture sur votre sélection, ou un autre attr comme data-readonly, et procédez comme suit
$("select[readonly]").live("focus mousedown mouseup click",function(e){
e.preventDefault();
e.stopPropagation();
});
En plus de désactiver les options qui ne devraient pas être sélectionnables, je voulais les faire disparaître de la liste, tout en pouvant les activer si j'avais besoin de plus tard:
$("select[readonly]").find("option:not(:selected)").hide().attr("disabled",true);
Cela trouve tous les éléments sélectionnés avec un attribut readonly, puis toutes les options à l'intérieur de ces sélections qui ne sont pas sélectionnées, puis les masque et les désactive.
Il est important de séparer la requête jquery en 2 pour des raisons de performances, car jquery les lit de droite à gauche, le code:
$("select[readonly] option:not(:selected)")
cherchera d’abord toutes les options non sélectionnées dans le document, puis filtrera celles qui se trouvent à l’intérieur de la sélection avec un attribut en lecture seule.
Si vous désactivez un champ de formulaire, celui-ci ne sera pas envoyé lorsque le formulaire est soumis. Donc, si vous avez besoin d'une readonly
qui fonctionne comme disabled
mais que vous envoyez des valeurs, procédez comme suit:
Après tout changement dans les propriétés en lecture seule d'un élément.
$('select.readonly option:not(:selected)').attr('disabled',true);
$('select:not([readonly]) option').removeAttr('disabled');
Une approche serveur simple consiste à supprimer toutes les options, à l'exception de celle que vous souhaitez sélectionner. Ainsi, dans Zend Framework 1.12, si $ element est un Zend_Form_Element_Select:
$value = $element->getValue();
$options = $element->getAttrib('options');
$sole_option = array($value => $options[$value]);
$element->setAttrib('options', $sole_option);
Solution avec tabindex. Fonctionne avec select mais aussi avec des entrées de texte.
Utilisez simplement une classe .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" />
Edit: Avec Internet Explorer, vous avez également besoin de ce JS:
$(document).on("mousedown", ".disabled", function (e) {
e.preventDefault();
});
Si vous utilisez jquery validate, vous pouvez procéder comme suit, j'ai utilisé l'attribut disabled sans problème:
$(function(){
$('#myform').validate({
submitHandler:function(form){
$('select').removeAttr('disabled');
form.submit();
}
});
});
Ce que j’ai trouvé fonctionne très bien, avec du javascript simple (c’est-à-dire qu’aucune bibliothèque JQuery n’est requise), c’est de changer le code innerHTML de la balise <select>
en la valeur unique restante souhaitée.
Avant:
<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>
Exemple de Javascript:
document.getElementById('day').innerHTML = '<option>FRI</option>';
Après:
<select name='day' id='day'>
<option>FRI</option>
</select>
De cette façon, aucun effet visuel ne changera, et cela POST/GET dans le <FORM>
.
Suite à la suggestion de Grant Wagners; Voici un extrait de code jQuery qui le fait avec des fonctions de gestionnaire au lieu d'attributs directs 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);
}
});
};
Je l'ai résolu avec jQuery:
$("select.myselect").bind("focus", function(){
if($(this).hasClass('readonly'))
{
$(this).blur();
return;
}
});
<select id="case_reason" name="case_reason" disabled="disabled">
disabled="disabled" ->
obtiendra votre valeur de la base de données dan et l'affichera sous la forme .readonly="readonly" ->
vous pourrez modifier votre valeur dans la zone de sélection, mais votre valeur ne pourrait pas être enregistrée dans votre base de données.
solution html:
<select onfocus="this.blur();">
les javascript:
selectElement.addEventListener("focus", selectElement.blur, true);
selectElement.attachEvent("focus", selectElement.blur); //thanks, IE
retirer:
selectElement.removeEventListener("focus", selectElement.blur, true);
selectElement.detachEvent("focus", selectElement.blur); //thanks, IE
edit: ajout de méthodes de suppression
Plutôt que la sélection elle-même, vous pouvez désactiver toutes les options à l'exception de l'option actuellement sélectionnée. Cela donne l’apparence d’un menu déroulant actif, mais seule l’option que vous souhaitez transmettre est une sélection valide.
Supprimez simplement l'attribut désactivé avant de soumettre le formulaire.
$('form').submit(function () {
$("#Id_Unidade").attr("disabled", false);
});
Ci-dessous a travaillé pour moi:
$('select[name=country]').attr("disabled", "disabled");
Je sais que cela n’aidera pas tout le monde (si vous êtes uniquement client), mais aidera ceux qui sont pleins et qui ont le contrôle du back-end et du front.
Si un utilisateur n'a pas le privilège de modifier un champ, je ne renvoie que la sélection actuelle pour la liste déroulante.
Voici quelques uns de mes contrôleurs backend:
#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
très simple. Première valeur de magasin dans la variable. Ensuite, lors de l'événement change, définissez la valeur sur la variable stockée contenant la valeur
J'ai un dont le nom est la cartographie. Ensuite, mon code sera comme suit;
$("document").ready(function(){
var mapping=$("select[name=mapping]").val();
$("select[name=mapping]").change(function(){
$("select[name=mapping]").val(mapping);
});
});
Dans IE, j'ai pu vaincre l’approche onfocus => onblur en double-cliquant sur .
<select onfocus="this.oldvalue=this.value;this.blur();" onchange="this.value=this.oldvalue;">
....
</select>
Vous pouvez faire la même chose sans les propriétés expando en utilisant une variable javascript.
Je l'ai géré en masquant la zone de sélection et en affichant une span
à sa place avec uniquement une valeur informative. En cas de désactivation de la classe .readonly
, nous devons également supprimer les éléments .toVanish
et afficher ceux .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()
}
});
var selectedOpt; // initialize var var newIdForHidden; // initialize var $ ('. disabledOnEdit'). focusin (function () { selectedOpt = $ (this) .find (": selected"). val (); newIdForHidden = $ (this) .attr ('id ') +' Caché '; //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) ; });
Si vous avez une étiquette de sélection qui doit être en lecture seule, vous devez logiquement transformer la zone de sélection en un seul champ "texte".
Je dis logiquement parce que c'est comme: "Je dois afficher une valeur à l'utilisateur"
Peu importe si la valeur provient d'une balise select, est toujours une valeur unique et ne peut pas être modifiée (en lecture seule).
Donc, logiquement, vous utilisez une balise select uniquement lorsque vous insérez la valeur pour la première fois.
Ensuite, lorsque vous devez afficher cette valeur, vous devez la placer sur un "champ de texte en lecture seule".
Identique pour une sélection multiple qui devient une liste de valeurs (la valeur sélectionnée) si en lecture seule
J'utilise "texte" parce qu'une balise readonly n'a pas besoin d'un attribut "type" .
Si le menu déroulant de sélection est en lecture seule depuis la naissance et n'a pas besoin de changer du tout, vous devriez peut-être utiliser un autre contrôle à la place? Comme un simple <div>
(plus un champ de formulaire caché) ou un <input type="text">
?
Ajouté: - Si le menu déroulant n'est pas en lecture seule tout le temps et que JavaScript est utilisé pour l'activer/le désactiver, il s'agit toujours d'une solution - il suffit de modifier le DOM à la volée.
Voici une tentative d'utilisation d'une fonction jQuery personnalisée pour obtenir la fonctionnalité (comme mentionné ici):
$(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);
});
select multiple ne répond pas aussi bien aux suggestions de code ci-dessus. Avec beaucoup de sledgehammering et kludging, je me suis retrouvé avec ceci:
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);
});
});