javascript - validacion - ¿Cómo continuar la propagación del evento después de cancelar?
validar formulario javascript html5 (6)
Debajo están los bits del código que realmente funcionó en Chrome 13, para mi sorpresa.
function handler (evt ) {
var t = evt.target;
...
setTimeout( function() {
t.dispatchEvent( evt )
}, 1000);
return false;
}
Esto no es muy cruzado de navegadores, y tal vez se solucione en el futuro, porque se siente como un riesgo de seguridad, ¿eh?
Y no sé lo que sucede, si cancelas la propagación del evento.
Cuando un usuario hace clic en un determinado enlace, me gustaría presentar un cuadro de diálogo de confirmación. Si hacen clic en "Sí", me gustaría continuar la navegación original. Una pega: mi diálogo de confirmación se implementa devolviendo un objeto jQuery.Deferred que se resuelve solo cuando / si el usuario hace clic en el botón Sí. Entonces, básicamente, el diálogo de confirmación es asincrónico.
Entonces, básicamente, quiero algo como esto:
$(''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
})
})
Por supuesto que podría establecer una bandera y volver a activar el clic, pero eso es desordenado como diablos. ¿Alguna forma natural de hacer esto?
Esto no se ha probado, pero podría servir como una solución para usted
$(''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
$(this).unbind(''click'').click()
})
})
Lo solucioné por:
- colocar un oyente de evento en un elemento padre
- eliminando la clase del enlace SÓLO cuando el usuario confirma
- volver a cerrar el enlace después de haber eliminado la clase.
function async() {
var dfd = $.Deferred();
// simulate async
setTimeout(function () {
if (confirm('' 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 razón por la que agregué el detector de eventos al padre y no al enlace en sí es porque el jQuery''s on
se vinculará al elemento hasta que se indique lo contrario. Entonces, aunque el elemento no tiene la clase another-page
, todavía tiene asociado el detector de eventos, por lo que debe aprovechar la event delegation
de event delegation
para resolver este problema.
GOTCHAS esto está muy basado en el estado. es decir, si necesita preguntar al usuario CADA VEZ que haga clic en un enlace, tendrá que agregar un segundo oyente para volver a leer la clase de another-page
en el enlace. es decir:
$(''body'').on(''click'', function (e) {
$(e.currentTarget).addClass(''another-page'');
});
Además, puede quitar el detector de eventos en el container
si el usuario acepta, si lo hace, asegúrese de usar eventos de namespace
porque puede haber otros oyentes en el contenedor que podría eliminar inadvertidamente. ver https://api.jquery.com/event.namespace/ para más detalles.
Resolví el problema de esta manera en uno de mis proyectos. Este ejemplo funciona con algún manejo básico de eventos como clics, etc. El controlador para la confirmación debe estar enlazado al primer controlador.
// 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 :)
Si entiendo el problema correctamente, creo que puedes actualizar el evento para que sea el evento original en ese cierre que tienes allí. Así que simplemente configure e = e.originalEvent en la función .done.
https://jsfiddle.net/oyetxu54/
MyApp.confirm("confirmation?")
.done(function(){ e = e.originalEvent;})
Aquí hay un violín con un ejemplo diferente (mantenga la consola abierta para que pueda ver los mensajes): esto funcionó para mí en Chrome y Firefox
Tenemos un requisito similar en nuestro proyecto y esto funciona para mí. Probado en Chrome e 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();
})
}
})