Événement sur une entrée désactivée

234

Apparemment, un handicapé <input>n'est géré par aucun événement

Existe-t-il un moyen de contourner ce problème?

<input type="text" disabled="disabled" name="test" value="test" />
$(':input').click(function () {
    $(this).removeAttr('disabled');
})

Ici, je dois cliquer sur l'entrée pour l'activer. Mais si je ne l'active pas, l'entrée ne doit pas être publiée.

Pierre de LESPINAY
la source
Voici une bonne alternative blog.pengoworks.com/index.cfm/2010/4/23/…
Vous pouvez utiliser le CSS-pretend-disable et boucler sur les entrées dans le gestionnaire onSubmit, désactivant les non-activées pour de vrai.
ptrk

Réponses:

267

Les éléments désactivés ne déclenchent pas les événements de souris. La plupart des navigateurs propageront un événement provenant de l'élément désactivé dans l'arborescence DOM, de sorte que les gestionnaires d'événements pourraient être placés sur des éléments de conteneur. Cependant, Firefox ne présente pas ce comportement, il ne fait rien du tout lorsque vous cliquez sur un élément désactivé.

Je ne peux pas penser à une meilleure solution mais, pour une compatibilité croisée complète entre les navigateurs, vous pouvez placer un élément devant l'entrée désactivée et attraper le clic sur cet élément. Voici un exemple de ce que je veux dire:

<div style="display:inline-block; position:relative;">
  <input type="text" disabled />
  <div style="position:absolute; left:0; right:0; top:0; bottom:0;"></div>
</div>​

jq:

$("div > div").click(function (evt) {
    $(this).hide().prev("input[disabled]").prop("disabled", false).focus();
});​

Exemple: http://jsfiddle.net/RXqAm/170/ (mis à jour pour utiliser jQuery 1.7 avec propau lieu de attr).

Andy E
la source
2
Petite chose: si vous utilisez l' disabledattribut sans valeur, cela implique HTML plutôt que XHTML, auquel cas la barre oblique de fermeture n'est pas nécessaire.
Tim Down
11
@Tim: en effet ce n'est pas nécessaire, mais c'est toujours du HTML valide. C'est juste une force d'habitude vraiment et j'ai l'impression que ça a l'air mieux.
Andy E
1
Thx Andy, c'est assez intelligent. N'est-ce pas plus simple? Savez-vous pourquoi les entrées désactivées ne sont pas gérables?
Pierre de LESPINAY
2
Cela n'a pas de sens: tout autre élément html gère les événements de la souris, pourquoi pas un élément désactivé (par exemple mouseenter, etc.)
Augustin Riedinger
7
Vous pouvez empêcher l'élément désactivé de "jeter" vos clics en mettant input[disabled] {pointer-events:none}votre CSS. Le clic se comporte alors comme si vous aviez cliqué sur l'élément parent. À mon humble avis , c'est la solution la plus simple et la plus propre, mais cela ne fonctionne malheureusement que pour les navigateurs qui prennent en charge la pointer-eventspropriété CSS: caniuse.com/#search=pointer-events
Doin
70

Vous pouvez peut-être rendre le champ en lecture seule et, sur soumettre, désactiver tous les champs en lecture seule

$(".myform").submit(function(e) {
    $("input[readonly]", this).attr("disabled", true);
});

et l'entrée (+ script) doit être

<input type="text" readonly="readonly" name="test" value="test" />

$('input[readonly]').click(function () {
    $(this).removeAttr('readonly');
})
Tokimon
la source
5
+1, c'est une suggestion alternative décente. Le seul inconvénient est que la zone de saisie ne prendra pas le style désactivé, qui varie selon les navigateurs, il serait donc difficile de la rendre cohérente avec les attentes de l'utilisateur d'une entrée désactivée.
Andy E
vrai. Peut-être que cela pourrait être résolu avec CSS? Mais oui, cela n'aurait pas le même aspect que les champs de saisie
normalisés
Excellente solution alternative. J'aime mieux celui-ci parce que vous pouvez faire tout style nécessaire avec CSS (c'est-à-dire le rendre LOOK désactivé) tout en ayant des événements disponibles.
Joshua
62

Les éléments désactivés "mangent" les clics dans certains navigateurs - ils ne répondent ni ne leur permettent d'être capturés par les gestionnaires d'événements n'importe où sur l'élément ou l'un de ses conteneurs.

À mon humble avis, le moyen le plus simple et le plus propre de "corriger" cela (si vous avez en fait besoin de capturer des clics sur des éléments désactivés comme le fait l'OP) consiste simplement à ajouter le CSS suivant à votre page:

input[disabled] {pointer-events:none}

Ainsi, tous les clics sur une entrée désactivée tomberont dans l'élément parent, où vous pourrez les capturer normalement. (Si vous avez plusieurs entrées désactivées, vous souhaiterez peut-être les placer chacune dans un conteneur individuel, si elles ne sont pas déjà disposées de cette façon - un supplément <span>ou un <div>, disons - juste pour faciliter la distinction entre les entrées désactivées a été cliqué).


L'inconvénient est que cette astuce ne fonctionnera malheureusement pas pour les navigateurs plus anciens qui ne prennent pas en charge la pointer-eventspropriété CSS. (Cela devrait fonctionner à partir d'IE 11, FF v3.6, Chrome v4): caniuse.com/#search=pointer-events

Si vous devez prendre en charge des navigateurs plus anciens, vous devrez utiliser l'une des autres réponses!

Doin
la source
Je ne savais pas si input[disabled]cela correspondrait également aux éléments désactivés par JavaScript ( element.disabled = true;), mais il semble que ce soit le cas. Quoi qu'il en soit, je trouve input:disabledplus propre.
Martin
Cela semble être une bonne solution, mais ne fonctionne pas pour moi dans IE11! Vous dites aussi FF 38+ et Chrome 31+ mais votre lien caniuse dit FF 3.6+ et Chrome 4+?
user764754
@ user764754 ... mon erreur, je ne m'étais pas rendu compte que je devais cliquer sur "Afficher tout" sur la page caniuse pour obtenir des versions antérieures du navigateur! J'ai corrigé ça. Quant à IE11, je viens de le tester et cela fonctionne très bien (voir jsfiddle.net/7kkszq1c/1 pour le code, bien que pour une raison quelconque le site jsFiddle ne fonctionnait pas pour moi dans IE11, j'ai dû le coller dans un fichier. fichier htm à la place)
Doin
Merci pour la mise à jour! En attendant, j'ai également observé que cela fonctionne sur un site Web dans IE11 mais pas avec jsfiddle. Peut-être à cause de l'iframe jsfiddle ...
user764754
2
@Protectorone: disabled est une pseudo-classe depuis CSS 3: w3.org/TR/css3-selectors/#UIstates
Martin
15

Je suggérerais une alternative - utilisez CSS:

input.disabled {
    user-select : none;
    -moz-user-select : none;
    -webkit-user-select : none;
    color: gray;
    cursor: pointer;
}

au lieu de l'attribut désactivé. Ensuite, vous pouvez ajouter vos propres attributs CSS pour simuler une entrée désactivée, mais avec plus de contrôle.

Ron Reiter
la source
4
ne fonctionne qu'avec ie10, trop d'utilisateurs ont ie9 / 8. donc pas une alternative fiable.
code le
Cela provoque toujours la publication du champ lorsque le formulaire est soumis, ce qui n'est pas souhaitable dans de nombreux cas.
cimmanon
7

$(function() {

  $("input:disabled").closest("div").click(function() {
    $(this).find("input:disabled").attr("disabled", false).focus();
  });

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>

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

Rejeesh Prarath
la source
5
Mais cela ne fonctionne pas sur FireFox - et c'était tout l'intérêt!
GarethOwen
6

Au lieu de disabled, vous pourriez envisager d'utiliser readonly. Avec du CSS supplémentaire, vous pouvez styliser l'entrée pour qu'elle ressemble à un disabledchamp.

Il y a en fait un autre problème. L'événement changene se déclenche que lorsque l'élément perd le focus, ce qui n'est pas logique compte tenu d'un disabledchamp. Vous insérez probablement des données dans ce champ à partir d'un autre appel. Pour que cela fonctionne, vous pouvez utiliser l'événement 'bind'.

$('form').bind('change', 'input', function () {
    console.log('Do your thing.');
});
Nykac
la source
Une entrée en lecture seule sera toujours soumise avec le formulaire si je ne me trompe pas
Pierre de LESPINAY
C'est correct. Il doit ensuite être combiné avec @npth anwsner.
Nykac
Merci, c'était intelligent, propre et optimisé pour mon cas.
Sultanos
4

OU faites-le avec jQuery et CSS!

$('input.disabled').attr('ignore','true').css({
    'pointer-events':'none',
     'color': 'gray'
});

De cette façon, vous désactivez l'élément et aucun événement de pointeur ne se déclenche, mais il permet la propagation et s'il est soumis, vous pouvez utiliser l'attribut «ignorer» pour l'ignorer.

sidonaldson
la source
@Precastic, c'est vrai, mais cela fonctionne pour presque tous les autres navigateurs à ce stade et vous pouvez utiliser un polyfill pour ie <11 . sidonaldson, pourquoi ne pas utiliser directement CSS pour appliquer des styles?
KyleMit du
@KyleMit, vous pourriez ajouter une classe plutôt que de définir les styles, mais ce n'est pas de cela qu'il s'agit! Je ne proposais que des événements de pointeur, ce qui est toujours une bonne et correcte réponse selon la matrice du navigateur pour laquelle vous construisez. Et merci à tous ceux qui ont noté cette réponse comme un peu nul, car rien ici n'est incorrect: /
sidonaldson
1
@sidonaldson, c'est une bonne réponse, je souhaite donc également qu'elle soit mieux classée. Je ne suis pas sûr de ce que fait l'attribut ignore . Mais mon point sur CSS était que je ne pense pas que jQuery soit le véhicule pour appliquer CSS. Vous pouvez simplement configurer une règle CSS ciblant le même sélecteur et également désactiver les événements de pointeur. Dans ce violon , jQuery et CSS devraient faire la même chose, mais le CSS sera beaucoup plus performant.
KyleMit
@KyleMit ah, en supposant bien que le formulaire soit soumis, vous devrez en quelque sorte dire au backend d'ignorer ce champ s'il contient une valeur (car nous usurpons la fonction de désactivation).
sidonaldson
Je suis d'accord que le CSS pourrait être plus puissant car vous pouvez utiliser un sélecteur basé sur un attribut! Regardez cette démo où j'ai fait correspondre le champ désactivé de chromes: jsfiddle.net/KyleMit/pxx8pk6v
sidonaldson
0

Nous avons eu aujourd'hui un problème comme celui-ci, mais nous ne voulions pas changer le HTML. Nous avons donc utilisé l' événement mouseenter pour y parvenir

var doThingsOnClick = function() {
    // your click function here
};

$(document).on({
    'mouseenter': function () {
        $(this).removeAttr('disabled').bind('click', doThingsOnClick);
    },
    'mouseleave': function () {
        $(this).unbind('click', doThingsOnClick).attr('disabled', 'disabled');
    },
}, 'input.disabled');
Raul Sanchez
la source
-1

Je trouve une autre solution:

<input type="text" class="disabled" name="test" value="test" />

La classe "désactivé" incite l'élément désactivé par l'opacité:

<style type="text/css">
    input.disabled {
        opacity: 0.5;
    }
</style>

Et puis annulez l'événement si l'élément est désactivé et supprimez la classe:

$(document).on('click','input.disabled',function(event) {
    event.preventDefault();
    $(this).removeClass('disabled');
});
npth
la source
La partie JavaScript ne fonctionne pas pour moi. En dehors de cela, il ne répond pas à la question, car il s'agit d'activer une entrée désactivée. Dans cet exemple, cependant, il n'est pas désactivé au début et est donc envoyé lors de la soumission.
Raimund Krämer