Dans Vanilla JavaScript, vous pouvez facilement activer et désactiver un bouton à l’aide de l’instruction suivante:
button.disabled = state;
Cela fonctionne à la fois lorsque les humains essaient de cliquer sur un bouton et lorsque l'utilisateur clique sur les boutons par programmation:
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')"/>
Cela fonctionne également lors de l'utilisation de l'interface 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')"/>
Je n'arrive pas à faire la même chose avec jQuery, cependant:
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')"/>
button.prop("disabled", true);
et button.attr("disabled", true);
modifient simplement la propriété disabled
de l'élément button, mais ne désactivent pas l'événement de clic réel. Cela signifie que les événements sont déclenchés à chaque appel de button.click();
, même si le bouton est désactivé!
De plus, "world" et "Hello" sont sortis dans le mauvais ordre.
Le code le plus simple que j'ai pu créer pour émuler le comportement des versions JavaScript de Vanilla est le suivant:
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')"/>
C’est, bien sûr, un code ridiculement compliqué et "hacky" pour réaliser quelque chose d'aussi simple que de désactiver un bouton.
Pour obtenir le résultat attendu, vous pouvez utiliser .isTrigger
dans le gestionnaire click
déclenché par jQuery afin de déterminer si l'événement est déclenché par javascript
et non par une action de l'utilisateur.
Définissez le programme d'écoute des événements d'attributs en tant que fonction nommée, où this
peut être passé pour vérifier la propriété disabled
à la condition if
si alert()
est appelé ou non.
Utilisez .attr("disabled", "disabled")
pour définir disabled
au niveau de l'élément, .removeAttr("disabled")
pour supprimer un attribut; .attr("onclick", null)
pour supprimer l'attribut d'événement onclick
handler; .attr("onclick", "handleClick(true)")
pour réinitialiser l'attribut d'événement.
<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 vous regardez jquery-1.12.4.js sur ces lignes:
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" ) ) {
Vous verrez un traitement différent des événements en fonction du type de délégation:
$(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>
Bien sûr, si vous attachez l'événement comme dans:
$('#btn').on("click", function() {
alert("world");
});
Le comportement est différent et semble étrange.
Vous appelez la fonction de clic directement 3 fois (button.click ()) qui se déclenche quel que soit l'attribut désactivé.
La propriété disabled ne répond qu'aux événements de clic.
Voir l'exemple mis à jour:
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" />
Utiliser .prop () est la bonne façon de le faire. Je pense que le problème réside dans la façon dont vous le "testez". Voir cet exemple où les boutons sont désactivés/activés correctement à l'aide du bouton bascule, que le gestionnaire soit attaché via onclick ou avec 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"/>
L’autre solution évidente consiste simplement à utiliser javascript dans Vanilla. Le fait que vous utilisiez jQuery ne signifie pas que tout "doit" être utilisé. Il y a certaines choses que vous pouvez faire sans jQuery.
EDIT: J'ai édité l'extrait de code montrant comment vous pouvez empêcher le .click () de jquery de déclencher les alertes.