web-dev-qa-db-fra.com

Formulaire HTML en lecture seule SELECT tag/input

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?

482
Jrgns

Vous devez conserver l'élément selectdisabled 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>

405
bezmax

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.

Démo

142
vimal1083

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

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

D&EACUTE;MO

46
Yaje
<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.

38
Grant Wagner

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

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.

19
d.raev

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

12
epeleg

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.

9
Leniel Maccaferri

Plus facile quand même: Ajoutez l'attribut style à votre balise select :

style="pointer-events: none;"
7
mainak chakraborty

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.

6
nrofis

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
5
Craig Ambrose

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

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.

5
cernunnos

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');
4
Joaquim Perez

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);
4
David

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

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

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

2
Syd

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

};
2
thetoolman

Je l'ai résolu avec jQuery:

      $("select.myselect").bind("focus", function(){
        if($(this).hasClass('readonly'))
        {
          $(this).blur();   
          return;
        }
      });
2
ownking
<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.

1
Afwan Zikri

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

1
Kadmillos

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.

1
Adam Bellaire

Supprimez simplement l'attribut désactivé avant de soumettre le formulaire.

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

Ci-dessous a travaillé pour moi:

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

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
0
Sam

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);
    });
});
0
ramesh shinde

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.

0
Sojourneer

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

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" .

0
Mindexperiment

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.

0
Vilx-

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

});
0
tamersalama

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