I want to control whether a link is clickable or an error should be displayed (Based on result of an ajax call).
<a class="lnkCustomer" href="http://localhost/viewcustomer" target="_blank" data-customerno="237">View</a>
I get to the point where I am able to set the link as "allowed to be clicked":
// Authorized
anchor.data("authorized", true);
However when I run this code, the link still does not open. Ideally once the ajax call is complete, it should invoke the click event. I believe the issue is in this line.
// Trigger Anchor
anchor.click();
This is the entire code:
<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>
Notes: I am using class instead of id in the anchor because I have various links that will trigger this event. However as you can see, this should not be an issue since I am always referring to the individual object:
var anchor = $(this);
I think we cannot overwrite the default behavior of the anchor tag but we can work around it. In this solution, I have replaced href with data-link. And mimic the anchor mechanism with window.open.
Code :
<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>
Please note :
preventDeault, but it do not workAnytime you want to override a browsers default action, you need to call .preventDefault() at the top of the event listener.
After that, since you're server side validating the link every time it's clicked, there's really no reason to store it's state client side. Instead of trying to re-click the link, you could just call window.open(), which is what achors do by default.
$('.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');
}
});
Try triggering click like this: anchor[0].click(); and see if that works.
For readability, you can save a reference to DOM element of anchor, not just the jQuery object:
var anchor = $(this);
var anchorEl = $(this)[0];
and trigger click using the DOM element:
anchorEl.click();
You cannot open a new tab without popups enabled or the user's click for that event. You cannot delay it with promises or invoke a trusted click event.
If you want to verify a user can click your link, then do the API request on page load and store the result.
Or make your link into a button with a two click process for checking and then opening.
AFAICT you are 90% of the way there, you're just missing a few key details.
e.preventDefault(): As already mentioned in other answers/comments, you need to prevent the default action which the event triggers, otherwise the browser will just begin the process of navigating to the link while your JS is still running.
anchor.click() will trigger a click on your link, which will ... start the whole process again! You'll get stuck in a recursive loop. The click is done, you now want to navigate. To open a new window in Javascript, use window.open(href, '_blank');
If your link is already authorised, you need to do the same as if the AJAX authorises it the first time around. Instead of return true;, you need to do the same window.open() again.
Also a suggestion - the convention for using GET or POST is:
AFAICT you are simply querying some customer details, so this should be a GET request.
I've modified you code to work with JSONPlaceholder - a dummy REST API which provides JSON data for this kind of situation (where we need to test an AJAX call with a working response), so we can simulate your AJAX call. It only accepts GET requests, so I've changed your POST to GET, and I've updated the test of the response based on the dummy data it sends back. You can see the output we're working with for User ID 1, and User ID 2.
Since you need to do the "go to the link" chunk of code in more than one place, I extracted that to a function you can call, so we don't need to duplicate that code in several places.
I also added a few extra alerts so you can be sure of what is happening.
See it all in action on 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>
There is a simple answer : you can't trigger a click if it doesn't come from a trusted event (change, click, dblclick, mouseup, reset, submit).
Here you are trying to trigger a click after an AJAX (asynchronous) request, which is not allowed.
More info here.
As suggested you could replace it by window.open(href, '_blank'); but beware it could also be blocked by the browser parameters.
Unfortunately, as others mentioned, href cannot be delayed. I did find a work-around to suit the particular scenario. I created an intermediary page when user clicks on the href. This page then performs the ajax request (server side), if it is validated it goes on and display the resource. Otherwise it displays an error and stays on the intermediary page.