formulario - how disable a button in javascript
Desactivando un botón en JavaScript vainilla y en jQuery (4)
Vanilla JavaScript
En JavaScript de vainilla, uno puede habilitar y deshabilitar fácilmente un botón usando la siguiente declaración:
button.disabled = state;
Esto funciona tanto cuando los seres humanos intentan hacer clic en un botón como cuando se hace clic en los botones mediante programación:
var button = document.getElementById(''myButton'');
button.addEventListener(''click'', function() {
alert(''world'');
});
button.disabled = true;
button.click(); // No output
button.disabled = false;
button.click(); // Output : "Hello" and "world
button.disabled = true;
button.click(); // No output
<input type="button" id="myButton" value="button" onClick="alert(''Hello'')"/>
Esto también funciona cuando se utiliza la interfaz MouseEvent
:
var button = document.getElementById(''myButton'');
var click = new MouseEvent("click", {
"view": window
});
button.addEventListener(''click'', function() {
alert(''world'');
});
button.disabled = true;
button.dispatchEvent(click); // No output
button.disabled = false;
button.dispatchEvent(click); // Output : "Hello" and "world
button.disabled = true;
button.dispatchEvent(click); // No output
<input type="button" id="myButton" value="button" onClick="alert(''Hello'')"/>
jQuery
Sin embargo, parece que no puedo hacer lo mismo con jQuery:
var button = $("#myButton");
button.on("click", function() {
alert("world");
});
button.prop("disabled", true);
button.click(); // Output : "world" and "Hello"
button.prop("disabled", false);
button.click(); // Output : "world" and "Hello"
button.prop("disabled", true);
button.click(); // Output : "world" and "Hello"
<script src="https://code.jquery.com/jquery-1.12.2.min.js"></script>
<input type="button" id="myButton" value="button" onClick="alert(''Hello'')"/>
Ambos button.prop("disabled", true);
y button.attr("disabled", true);
simplemente cambie la propiedad disabled
del elemento de botón, pero ninguno deshabilita el evento de clic real. Esto significa que los eventos se activan siempre que button.click();
se llama, incluso si el botón está deshabilitado!
Además, "mundo" y "Hola" se muestran en el orden incorrecto.
El código más simple que se me ocurre para emular el comportamiento de las versiones de JavaScript de vainilla es el siguiente:
var button = $("#myButton");
button.on("click", function() {
alert("world");
});
button.disable = (function() {
var onclick = null;
var click = [];
return function(state) {
if(state) {
this.prop(''disabled'', true);
if(this.prop(''onclick'') !== null) {
onclick = this.prop(''onclick'');
this.prop(''onclick'', null);
}
var listeners = $._data(this.get()[0], "events");
listeners = typeof listeners === ''undefined'' ? [] : listeners[''click''];
if(listeners && listeners.length > 0) {
for(var i = 0; i < listeners.length; i++) {
click.push(listeners[i].handler);
}
this.off(''click'');
}
} else {
this.removeProp(''disabled'');
if(onclick !== null) {
this.prop(''onclick'', onclick);
onclick = null;
}
if(click.length > 0) {
this.off(''click'');
for(var i = 0; i < click.length; i++) {
this.on("click", click[i]);
}
click = [];
}
}
}
})();
button.disable(true);
button.click(); // No output
button.disable(false);
button.click(); // Output : "Hello" and "world
button.disable(true);
button.click(); // No output
<script src="https://code.jquery.com/jquery-1.12.2.min.js"></script>
<input type="button" id="myButton" value="button" onClick="alert(''Hello'')"/>
Eso es, por supuesto, un código ridículamente intrincado y "pirateado" para lograr algo tan simple como deshabilitar un botón.
Mis preguntas
- ¿Por qué es que jQuery, a diferencia de vanilla JS, no deshabilita los eventos al deshabilitar un botón?
- ¿Es esto para ser considerado un error o una característica en jQuery?
- ¿Hay algo que estoy pasando por alto?
- ¿Hay una forma más sencilla de obtener el comportamiento esperado en jQuery?
Está llamando a la función de clic directamente 3 veces (button.click ()) que se activa independientemente del atributo deshabilitado.
La propiedad deshabilitada solo responde a los eventos clic.
Vea el ejemplo actualizado:
var button = $("#myButton");
var button2 = $("#myButton2");
button.prop("disabled", false);
button.on("click", function() {
alert("world");
button2.prop("disabled", false);
});
button2.prop("disabled", true);
button2.on("click", function() {
alert("world");
button.prop("disabled", true);
});
<script src="https://code.jquery.com/jquery-1.12.2.min.js"></script>
<input type="button" id="myButton" value="button" onClick="alert(''Hello'')"/>
<input type="button" id="myButton2" value="button2" />
Para lograr el resultado esperado, puede utilizar .isTrigger
dentro del controlador de click
activado por jQuery para determinar si el evento es activado por javascript
y no por la acción del usuario.
Defina el detector de eventos de atributos como una función con nombre, donde se puede pasar para verificar la propiedad disabled
en la condición if si se llama alert()
, o no se llama.
Use .attr("disabled", "disabled")
para establecer disabled
en el elemento, .removeAttr("disabled")
para eliminar el atributo; .attr("onclick", null)
para eliminar el atributo de evento onclick
handler; .attr("onclick", "handleClick(true)")
para restablecer el atributo del evento.
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<input type="button" id="myButton" value="button" onclick="handleClick(this)" />
<script>
function handleClick(el) {
if (el.disabled !== "disabled")
alert("Hello")
}
var button = $("#myButton");
button.on("click", function(e) {
console.log(e);
if (e.isTrigger !== 3 && !e.target.disabled)
alert("world");
});
button.attr("disabled", "disabled");
button.attr("onclick", null);
button.click(); // no output
setTimeout(function() {
button.removeAttr("disabled");
button.attr("onclick", "handleClick(button[0])");
button.click(); // Output : "world" and "Hello"
// click button during 9000 between `setTimeout` calls
// to call both jQuery event and event attribute
}, 1000);
setTimeout(function() {
button.attr("disabled", "disabled");
button.attr("onclick", null);
button.click(); // no output
}, 10000);
</script>
Si jquery-1.12.4.js un vistazo a jquery-1.12.4.js en estas líneas:
handlers: function( event, handlers ) {
var i, matches, sel, handleObj,
handlerQueue = [],
delegateCount = handlers.delegateCount,
cur = event.target;
// Support (at least): Chrome, IE9
// Find delegate handlers
// Black-hole SVG <use> instance trees (#13180)
//
// Support: Firefox<=42+
// Avoid non-left-click in FF but don''t block IE radio events (#3861, gh-2343)
if ( delegateCount && cur.nodeType &&
( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) {
/* jshint eqeqeq: false */
for ( ; cur != this; cur = cur.parentNode || this ) {
/* jshint eqeqeq: true */
// Don''t check non-elements (#13208)
// Don''t process clicks on disabled elements (#6911, #8165, #11382, #11764)
if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) {
Verá un manejo diferente de los eventos según el tipo de delegación:
$(document).on("click", ''#btn'', function() {
console.log("world");
});
$(function () {
$(''#btnToggle'').on(''click'', function(e) {
$(''#btn'').prop(''disabled'', !$(''#btn'').prop(''disabled''));
});
$(''#btnTestClick'').on(''click'', function(e) {
$(''#btn'').click();
});
});
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<button id="btn">Click Me</button>
<button id="btnToggle">Enable/Disable button</button>
<button id="btnTestClick">Test Click</button>
Por supuesto, si adjuntas el evento como en:
$(''#btn'').on("click", function() {
alert("world");
});
El comportamiento es diferente y parece extraño.
Usar .prop () es la forma correcta de hacerlo. Creo que el problema está en la forma en que lo estás "probando". Vea este ejemplo donde los botones están deshabilitados / habilitados correctamente usando el botón de alternar independientemente de si el controlador se adjunta mediante onclick o con jquery.
window.testFunc = function(event) {
if (!$(''#myButton2'').prop(''disabled'')) {
alert("hello");
console.log("hello");
}
}
$(document).ready(function() {
var button = $("#myButton2");
button.on("click", function(event) {
if (!$(this).prop(''disabled'')) {
alert("world");
console.log("world");
}
});
$(''#toggleButton'').click(function() {
$(''#myButton1'').prop(''disabled'', !$(''#myButton1'').prop(''disabled''));
$(''#myButton2'').prop(''disabled'', !$(''#myButton2'').prop(''disabled''));
});
$(''#tester'').click(function() {
$(''#myButton1'').click();
$(''#myButton2'').click();
});
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="button" id="myButton1" value="vanilla button (hello)" onclick="window.testFunc(event)"/>
<input type="button" id="myButton2" value="jquery button (world)"/>
<input type="button" id="toggleButton" value="toggle disabled"/>
<input type="button" id="tester" value="test the buttons"/>
La otra solución obvia es usar javascript de vainilla. El hecho de que esté utilizando jQuery no significa que todo "debe" haber terminado de usarlo. Hay algunas cosas que se pueden hacer sin jQuery.
EDITAR: edité el fragmento que muestra cómo se podría evitar que .click () de jquery active las alertas.