Lorsqu'un utilisateur clique sur un certain lien, je souhaite lui présenter une boîte de dialogue de confirmation. S'ils cliquent sur "Oui", j'aimerais continuer la navigation d'origine. Une capture: ma boîte de dialogue de confirmation est implémentée en renvoyant un objet jQuery.Deferred qui est résolu uniquement lorsque/si l'utilisateur clique sur le bouton Oui. La boîte de dialogue de confirmation est donc asynchrone.
Donc, fondamentalement, je veux quelque chose comme ça:
$('a.my-link').click(function(e) {
e.preventDefault(); e.stopPropogation();
MyApp.confirm("Are you sure you want to navigate away?")
.done(function() {
//continue propogation of e
})
})
Bien sûr, je pourrais définir un drapeau et re-déclencher le clic, mais c'est vraiment compliqué. Une manière naturelle de faire ça?
Vous trouverez ci-dessous les éléments du code qui fonctionnaient dans Chrome 13, à ma grande surprise.
function handler (evt ) {
var t = evt.target;
...
setTimeout( function() {
t.dispatchEvent( evt )
}, 1000);
return false;
}
Ce n'est pas très multi-navigateur, et sera peut-être corrigé à l'avenir, car cela ressemble à un risque de sécurité, à mon humble avis.
Et je ne sais pas ce qui se passe si vous annulez la propagation d'événements.
Si je comprends bien le problème, je pense que vous pouvez simplement mettre à jour l'événement pour qu'il s'agisse de l'événement d'origine dans la fermeture que vous avez là. Il suffit donc de définir e = e.originalEvent dans la fonction .done.
https://jsfiddle.net/oyetxu54/
MyApp.confirm("confirmation?")
.done(function(){ e = e.originalEvent;})
voici un violon avec un exemple différent (laissez la console ouverte pour pouvoir voir les messages): cela a fonctionné pour moi en chrome et firefox
J'ai résolu le problème de cette façon sur l'un de mes projets. Cet exemple fonctionne avec certaines opérations de base telles que les clics, etc. Le gestionnaire de confirmation doit être lié au premier gestionnaire.
// This example assumes clickFunction is first event handled.
//
// you have to preserve called function handler to ignore it
// when you continue calling.
//
// store it in object to preserve function reference
var ignoredHandler = {
fn: false
};
// function which will continues processing
var go = function(e, el){
// process href
var href = $(el).attr('href');
if (href) {
window.location = href;
}
// process events
var events = $(el).data('events');
for (prop in events) {
if (events.hasOwnProperty(prop)) {
var event = events[prop];
$.each(event, function(idx, handler){
// do not run for clickFunction
if (ignoredHandler.fn != handler.handler) {
handler.handler.call(el, e);
}
});
}
}
}
// click handler
var clickFunction = function(e){
e.preventDefault();
e.stopImmediatePropagation();
MyApp.confirm("Are you sure you want to navigate away?")
.done(go.apply(this, e));
};
// preserve ignored handler
ignoredHandler.fn = clickFunction;
$('.confirmable').click(clickFunction);
// a little bit longer but it works :)
Nous avons une exigence similaire dans notre projet et cela fonctionne pour moi. Testé en chrome et IE11.
$('a.my-link').click(function(e) {
e.preventDefault();
if (do_something === true) {
e.stopPropogation();
MyApp.confirm("Are you sure you want to navigate away?")
.done(function() {
do_something = false;
// this allows user to navigate
$(e.target).click();
})
}
})
J'ai édité votre code. Nouvelles fonctionnalités que j'ai ajoutées:
Code:
$('a.my-link').on("click.myEvent", function(e) {
var $that = $(this);
$that.off("click.myEvent");
e.preventDefault();
e.stopImmediatePropagation();
MyApp.confirm("Are you sure you want to navigate away?")
.done(function() {
//continue propogation of e
$that.trigger("click");
});
});
J'ai résolu ceci par:
function async() {
var dfd = $.Deferred();
// simulate async
setTimeout(function () {
if (confirm('Stackoverflow FTW')) {
dfd.resolve();
} else {
dfd.reject();
}
}, 0);
return dfd.promise();
};
$('.container').on('click', '.another-page', function (e) {
e.stopPropagation();
e.preventDefault();
async().done(function () {
$(e.currentTarget).removeClass('another-page').click();
});
});
$('body').on('click', function (e) {
alert('navigating somewhere else woot!')
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<a href="#" class="another-page">Somewhere else</a>
</div>
La raison pour laquelle j'ai ajouté l'écouteur d'événement au parent et non au lien lui-même, c'est parce que l'événement on
de jQuery sera lié à l'élément jusqu'à indication contraire. Ainsi, même si l'élément n'a pas la classe another-page
, l'écouteur d'événements est toujours attaché. Vous devez donc tirer parti de event delegation
pour résoudre ce problème.
GOTCHAS c'est très basé sur l'état. C'est-à-dire que si vous devez demander à l'utilisateur CHAQUE FOIS, ils cliquent sur un lien, vous devrez ajouter un deuxième écouteur pour relire la classe another-page
dans le lien. c'est à dire.:
$('body').on('click', function (e) {
$(e.currentTarget).addClass('another-page');
});
note latérale vous pouvez également supprimer l'écouteur d'événements sur container
si l'utilisateur accepte, si vous le faites, assurez-vous d'utiliser les événements namespace
car il pourrait y avoir d'autres écouteurs sur le conteneur que vous pourriez supprimer par inadvertance. voir https://api.jquery.com/event.namespace/ pour plus de détails.