Evento em uma entrada desativada

234

Aparentemente, um deficiente <input>não é tratado por nenhum evento

Existe uma maneira de contornar esse problema?

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

Aqui, preciso clicar na entrada para habilitá-la. Mas se eu não ativá-lo, a entrada não deve ser postada.

Pierre de LESPINAY
fonte
Aqui está uma boa alternativa blog.pengoworks.com/index.cfm/2010/4/23/…
Você pode usar o CSS-fingir-desativar e fazer um loop sobre as entradas no manipulador onSubmit, desativando as não ativadas de verdade.
Ptrk

Respostas:

267

Elementos desativados não acionam eventos do mouse. A maioria dos navegadores propagará um evento originado do elemento desativado na árvore DOM, para que os manipuladores de eventos possam ser colocados nos elementos do contêiner. No entanto, o Firefox não exibe esse comportamento, apenas não faz nada quando você clica em um elemento desativado.

Não consigo pensar em uma solução melhor, mas, para uma compatibilidade completa entre navegadores, você pode colocar um elemento na frente da entrada desativada e clicar no elemento. Aqui está um exemplo do que quero dizer:

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

Exemplo: http://jsfiddle.net/RXqAm/170/ (atualizado para usar o jQuery 1.7 em propvez de attr).

Andy E
fonte
2
Pequena coisa: se você estiver usando o disabledatributo sem valor, isso implica HTML em vez de XHTML; nesse caso, a barra final é desnecessária.
Tim Baixo
11
@ Tim: na verdade, é desnecessário, mas ainda é HTML válido. É apenas uma força do hábito e sinto que parece melhor.
Andy E
1
Thx Andy, isso é bastante inteligente. Não existe mais simples? Você sabe por que as entradas desabilitadas não podem ser manuseadas?
Pierre de LESPINAY
2
Isso não faz sentido: quaisquer outros eventos alças rato elemento html, por que não um elemento de pessoas com deficiência (por exemplo. mouseenter, Etc.)
Augustin Riedinger
7
Você pode impedir que o elemento desativado "jogue fora" seus cliques inserindo input[disabled] {pointer-events:none}seu CSS. Em seguida, o clique se comporta como se você tivesse clicado no elemento pai. IMHO esta é a solução mais simples, mais limpa, mas infelizmente só funciona para navegadores que suportam a pointer-eventspropriedade CSS: caniuse.com/#search=pointer-events
Doin
70

Talvez você possa tornar o campo somente leitura e, ao enviar, desabilitar todos os campos somente leitura

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

e a entrada (+ script) deve ser

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

$('input[readonly]').click(function () {
    $(this).removeAttr('readonly');
})
Tokimon
fonte
5
+1, esta é uma sugestão alternativa decente. A única desvantagem é que a caixa de entrada não assume o estilo desabilitado, que varia entre os navegadores, portanto, seria difícil torná-la consistente com as expectativas do usuário de uma entrada desabilitada.
Andy E
verdade. Talvez isso possa ser resolvido com CSS? Mas sim, não teria a mesma aparência como campos de entrada diabled normais
Tokimon
Excelente solução alternativa. Eu gosto mais deste porque você pode fazer qualquer estilo necessário com CSS (ou seja, torná-lo desativado) e ainda assim ter eventos disponíveis.
217 Joshua Joshua
62

Elementos desativados "comem" cliques em alguns navegadores - eles não respondem a eles nem permitem que sejam capturados pelos manipuladores de eventos em qualquer lugar do elemento ou de seus contêineres.

IMHO, a maneira mais simples e limpa de "consertar" isso (se você realmente precisa capturar cliques em elementos desabilitados como o OP faz) é apenas adicionar o seguinte CSS à sua página:

input[disabled] {pointer-events:none}

Isso fará com que todos os cliques em uma entrada desabilitada caiam no elemento pai, onde você pode capturá-los normalmente. (Se você tiver várias entradas desativadas, poderá colocar cada uma em um contêiner individual próprio, se elas ainda não estiverem dispostas dessa maneira - uma extra <span>ou uma <div>, digamos - apenas para facilitar a distinção de quais entradas desativadas foi clicado).


A desvantagem é que, infelizmente, esse truque não funciona em navegadores antigos que não suportam a pointer-eventspropriedade CSS. (Ele deve funcionar no IE 11, FF v3.6, Chrome v4): caniuse.com/#search=pointer-events

Se você precisar dar suporte a navegadores mais antigos, precisará usar uma das outras respostas!

Doin
fonte
Eu não tinha certeza se input[disabled]também corresponderia aos elementos desativados pelo JavaScript ( element.disabled = true;), mas parece que sim. Enfim, acho input:disabledmais limpo.
Martin Martin
Parece uma boa solução, embora não funcione para mim no IE11! Você também diz FF 38+ e Chrome 31+, mas seu link caniuse diz FF 3.6+ e Chrome 4+?
user764754
@ user764754 ... meu erro, eu não sabia que precisava clicar em "Mostrar tudo" na página de caniuse para obter versões anteriores do navegador! Conserte isso. Quanto ao IE11, eu apenas testei e ele funciona bem (consulte jsfiddle.net/7kkszq1c/1 para obter o código, embora por alguma razão o site jsFiddle não funcione para mim no IE11, eu tive que colá-lo em um arquivo. arquivo htm)
Doin
Obrigado pela atualização! Enquanto isso, observei também que ele funciona em um site no IE11, mas não com o jsfiddle. Talvez por causa do
ifsrame
2
@Protectorone: disabled é uma pseudo-classe desde CSS 3: w3.org/TR/css3-selectors/#UIstates
Martin
15

Eu sugeriria uma alternativa - use CSS:

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

em vez do atributo desativado. Em seguida, você pode adicionar seus próprios atributos CSS para simular uma entrada desativada, mas com mais controle.

Ron Reiter
fonte
4
só funciona com ie10, muitos usuários têm ie9 / 8. portanto, não é uma alternativa confiável.
codifica
Isso ainda faz com que o campo seja postado quando o formulário é enviado, o que é indesejável em muitos casos.
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
fonte
5
Mas isso não funciona no FireFox - e esse era o ponto!
GarethOwen
6

Em vez de disabled, você pode considerar usar readonly. Com algum CSS extra, você pode estilizar a entrada para que ela pareça um disabledcampo.

Na verdade, há outro problema. O evento changesomente dispara quando o elemento perde o foco, o que não é lógico considerando um disabledcampo. Provavelmente você está enviando dados para esse campo a partir de outra chamada. Para fazer isso funcionar, você pode usar o evento 'bind'.

$('form').bind('change', 'input', function () {
    console.log('Do your thing.');
});
Nykac
fonte
Uma entrada somente leitura ainda será enviada com o formulário, se não me engano
Pierre de LESPINAY
Está correto. Em seguida, ele deve ser combinado com o @npth anwsner.
Nykac 8/08
Obrigado, isso foi inteligente, limpo e otimizado para o meu caso.
Sultanos
4

OU faça isso com jQuery e CSS!

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

Dessa forma, você faz com que o elemento pareça desabilitado e nenhum evento de ponteiro será acionado, mas ele permitirá a propagação e, se enviado, você poderá usar o atributo 'ignorar' para ignorá-lo.

sidonaldson
fonte
@Precastic, isso é verdade, mas funciona para quase todos os outros navegadores nesse momento e você pode usar um polyfill por <11 . sidonaldson, por que não usar CSS direto para aplicar estilos?
KyleMit 26/10
@KyleMit, você pode adicionar uma classe em vez de definir os estilos, mas não é disso que se trata este tópico! Eu estava apenas sugerindo eventos de ponteiro, que ainda é uma resposta boa e correta, dependendo da matriz do navegador para a qual você está construindo. E obrigado por todos que marcaram esta resposta que meio que é péssimo, porque nada aqui está incorreto: /
sidonaldson
1
@ Sidneyson, é uma boa resposta, então eu também gostaria que fosse classificada mais alta também. Não tenho certeza do que o atributo ignore faz . Mas o que quero dizer sobre CSS é que não acho que precisamos do jQuery para ser o veículo para a aplicação de CSS. Você pode simplesmente configurar uma regra CSS que tenha como alvo o mesmo seletor e também desabilite os eventos do ponteiro. Nesse violino , o jQuery e o CSS devem estar fazendo a mesma coisa, mas o CSS terá muito mais desempenho.
KyleMit
@KyleMit ah, bem, supondo que o formulário seja enviado, você precisará dizer de alguma forma ao back-end que ignore esse campo se ele contiver um valor (já que estamos falsificando desativados).
Sidneyson 28/10
Concordo que o CSS poderia ser mais poderoso, pois você pode usar um seletor com base em um atributo! Confira esta demonstração onde eu combinava cromos próprio campo desativado: jsfiddle.net/KyleMit/pxx8pk6v
sidonaldson
0

Hoje tivemos um problema como este, mas não queríamos mudar o HTML. Então, usamos o evento mouseenter para conseguir isso

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
fonte
-1

Eu encontro outra solução:

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

A classe "desabilitada" imita o elemento desabilitado por opacidade:

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

E, em seguida, cancele o evento se o elemento estiver desativado e remova a classe:

$(document).on('click','input.disabled',function(event) {
    event.preventDefault();
    $(this).removeClass('disabled');
});
npth
fonte
A parte do JavaScript não funciona para mim. Além disso, ele não responde à pergunta, pois trata-se de ativar uma entrada desativada. Neste exemplo, no entanto, ele não está desativado no início e, portanto, é enviado no envio.
Raimund Krämer