Quiero controlar si se puede hacer clic en un enlace o si se debe mostrar un error (según el resultado de una llamada ajax).
<a class="lnkCustomer" href="http://localhost/viewcustomer" target="_blank" data-customerno="237">View</a>Llego al punto en el que puedo configurar el enlace como "permitido hacer clic":
// Authorized anchor.data("authorized", true);Sin embargo, cuando ejecuto este código, el enlace aún no se abre. Idealmente, una vez que se completa la llamada ajax, debería invocar el evento de clic. Creo que el problema está en esta línea.
// Trigger Anchor anchor.click();Este es el código completo:
<script type="text/javascript"> $(".lnkCustomer").click(function(e) { var customerNo = $(this).data('customerno'); var anchor = $(this); // Check for authorized if (anchor.data("authorized")) { return true; } $.ajax( { url: 'http://localhost/checkcustomer', type: 'POST', dataType: 'json', data: { customerNo: customerNo }, cache: false, success: function (result) { if (result.success) { // Authorize anchor.data("authorized", true); // Trigger Anchor anchor.click(); } else { // Show a message in a alert or div alert('Not authorized'); } } }); // Default to false (Do not process anchor) return false; }); </script>Notas: estoy usando class en lugar de id en el ancla porque tengo varios enlaces que activarán este evento. Sin embargo, como puede ver, esto no debería ser un problema ya que siempre me refiero al objeto individual:
var anchor = $(this);Creo que no podemos sobrescribir el comportamiento predeterminado de la etiqueta de anclaje, pero podemos solucionarlo. En esta solución, he reemplazado href con data-link . E imite el mecanismo de anclaje con window.open .
Código:
<a class="lnkCustomer" data-link="http://localhost/viewcustomer1" data-customerno="111" data-auth>View</a> <a class="lnkCustomer" data-link="http://localhost/viewcustomer2" data-customerno="237" data-auth>View</a> <a class="lnkCustomer" data-link="http://localhost/viewcustomer3" data-customerno="237" data-auth>View</a> <script type="text/javascript"> $(".lnkCustomer").click(function (e) { var customerNo = $(this).data('customerno'); var linkToGo = $(this).data('link'); var anchor = $(this); // Check for authorized if (anchor.data("authorized")) { var win = window.open(linkToGo, '_blank'); }else{ $.ajax( { url: './checkcustomer.php', type: 'POST', data: { customerNo: customerNo }, cache: false, success: function (result) { if (result == 'authorized') { anchor.data("authorized", true); //new code anchor.attr("href", linkToGo); anchor.click(); // Dont us this due to popup blocker //var win = window.open(linkToGo, '_blank'); } else { // Show a message in a alert or div alert('Not authorized'); } } }); } }); </script>Tenga en cuenta :
preventDeault , pero no funcionóCada vez que desee anular una acción predeterminada de los navegadores, debe llamar a .preventDefault() en la parte superior del detector de eventos.
Después de eso, dado que está del lado del servidor validando el enlace cada vez que se hace clic en él, realmente no hay razón para almacenar su estado del lado del cliente. En lugar de intentar volver a hacer clic en el enlace, simplemente puede llamar a window.open() , que es lo que hacen los anclajes de forma predeterminada.
$('.lnkCustomer').on('click', function(e) { e.preventDefault(); //makes anchor click do nothing let href = this.href; //pretend this is the call back from your ajax call //$.ajax( // success: function(result) { if (result.success) { window.open(href, '_blank'); //what an anchor click does when not prevented } else { alert('Not authorized'); } });Intente activar un clic como este: anchor[0].click(); y ver si eso funciona.
Para facilitar la lectura, puede guardar una referencia al elemento DOM del ancla, no solo al objeto jQuery:
var anchor = $(this); var anchorEl = $(this)[0];y activa el clic usando el elemento DOM:
anchorEl.click();No puede abrir una nueva pestaña sin las ventanas emergentes habilitadas o el clic del usuario para ese evento. No puede retrasarlo con promesas o invocar un evento de clic confiable.
Si desea verificar que un usuario pueda hacer clic en su enlace, realice la solicitud de API en la carga de la página y almacene el resultado.
O convierta su enlace en un botón con un proceso de dos clics para verificar y luego abrir.
ASUNTO, has recorrido el 90 % del camino, solo te faltan algunos detalles clave.
e.preventDefault() : como ya se mencionó en otras respuestas/comentarios, debe evitar la acción predeterminada que desencadena el evento; de lo contrario, el navegador simplemente comenzará el proceso de navegar hasta el enlace mientras su JS aún se está ejecutando.
anchor.click() activará un clic en su enlace, que ... ¡comenzará todo el proceso de nuevo! Te quedarás atrapado en un bucle recursivo. El clic está hecho, ahora desea navegar. Para abrir una nueva ventana en Javascript , use window.open(href, '_blank');
Si su enlace ya está autorizado, debe hacer lo mismo que si AJAX lo autorizara la primera vez. En lugar de return true; , debe hacer lo mismo window.open() nuevamente.
También una sugerencia: la convención para usar GET o POST es:
AFICTO, simplemente está consultando algunos detalles del cliente, por lo que debería ser una solicitud GET.
Modifiqué su código para que funcione con JSONPlaceholder , una API REST ficticia que proporciona datos JSON para este tipo de situación (donde necesitamos probar una llamada AJAX con una respuesta funcional), para que podamos simular su llamada AJAX. Solo acepta solicitudes GET, por lo que cambié su POST a GET y actualicé la prueba de la respuesta en función de los datos ficticios que devuelve. Puede ver el resultado con el que estamos trabajando para el ID de usuario 1 y el ID de usuario 2 .
Como necesita hacer el fragmento de código "ir al enlace" en más de un lugar, lo extraje a una función a la que puede llamar, por lo que no necesitamos duplicar ese código en varios lugares.
También agregué algunas alertas adicionales para que pueda estar seguro de lo que está sucediendo.
Véalo todo en acción en JSFiddle .
JavaScript:
// A function to actually open the new page, since we need to do this in // more than one place. function goToLink(anchor) { let href=anchor.attr('href'); window.open(href, '_blank'); } $(".lnkCustomer").click(function(e) { // Prevent the default action this event would normally trigger from // happening - in this case, navigating to the target href. e.preventDefault(); var customerNo = $(this).data('customerno'); var anchor = $(this); // Check for authorized, and open the link if so if (anchor.data("authorized")) { alert("Already authorized, let's go!"); goToLink(anchor); } // https://jsonplaceholder.typicode.com/ is a dummy REST JSON generator. // Let's use it to simulate your AJAX call. User ID 1's username is Bret, // user ID 2's username is Antonette. Let's use customerNo in the URL to // retrieve user ID 1 or 2, and simply allow the click if the username is // Antonette. // First build the URL: let url = 'https://jsonplaceholder.typicode.com/users/' + customerNo $.ajax({ url: url, type: 'GET', dataType: 'json', data: { customerNo: customerNo }, cache: false, success: function(result) { if (result.username === 'Antonette') { // Authorize and go alert("Authorization success, let's go!"); anchor.data("authorized", true); goToLink(anchor); } else { // Show a message in a alert or div alert('Not authorized'); } } }); // Default to false (Do not process anchor) return false; });HTML:
<ul> <li><a class="lnkCustomer" href="https://google.com/" target="_blank" data-customerno="1">Google (no go)</a></li> <li><a class="lnkCustomer" href="https://stackoverflow.com/" target="_blank" data-customerno="2">Stackoverflow (allowed)</a></li> </ul>Hay una respuesta simple: no puede activar un clic si no proviene de un evento confiable (cambio, clic, doble clic, mouseup, reinicio, envío).
Aquí está intentando activar un clic después de una solicitud AJAX (asíncrona), que no está permitida.
Más información aquí .
Como se sugirió, podría reemplazarlo por window.open(href, '_blank'); pero cuidado, también podría estar bloqueado por los parámetros del navegador.
Desafortunadamente, como mencionaron otros, href no se puede retrasar. Encontré una solución alternativa para adaptarse al escenario particular. Creé una página intermedia cuando el usuario hace clic en href. Esta página luego realiza la solicitud ajax (lado del servidor), si se valida, continúa y muestra el recurso. De lo contrario, muestra un error y permanece en la página intermedia.