Control whether a link is clickable or not - javascript

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);

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.

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.

Anytime 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();

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 :
New note for security: As you can see we are using quite a visible data-link and anyone with enough effort can visit the link whether it is authorized or not. If the above answer gets you through the popup blocker, the next few things you can do is maybe only fetch accessible links from the start
OR add a "show links" button and then fetch only accessible links to the user. You can do it via ajax. and also you will not need this JS/Jquery code.
OR assign a random number to data-link and then fetch in your PHP code see if it is authorized if it is then only return accessible HTTP link. many ways to improve.
You can use CSS to style the anchor tags, which I have not in the solution
One method I tried was with use of preventDeault, but it do not work

AFAICT you are 90% of the way there, you're just missing a few key details.
Working JSFiddle.
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:
use POST when changing data, eg creating a user, or making a purchase, logging in - something which should not happen 2x if you hit reload;
use GET when viewing data, no state changes, no harm in reloading;
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>

Related

Href to Onclick redirect

I have research this topic through the community, although I cannot find an answer. I am using Bronto's direct add feature (attempting to use it), The documentation isn't that great.
In summary, the href link subscribes the user on the email list. The only problem is that this link opens a new page. When I want the user to stay on the same page. I though about doing a redirect, when clicking the link, though I am not sure if that would work.
I have tried this:
//Html
<a id="subscription" href="http://example.com">Subscribe</a>
// Jquery
$("#emailsubscribe").click(function(e){
e.preventDefault();//this will prevent the link trying to navigate to another page
//do the update
var href = "http://example.com";
//when update has finished, navigate to the other page
window.location = "href";
});
The goal is that I am trying to make it where the user clicks on the link, it subscribes them to the email list, but immediately redirects them back, without opening another window.
You're looking for AJAX. This allows you to make requests without actually navigating to a page. Since you're using jQuery
$("#emailSubscribe").click(function (e) {
e.preventDefault();
$.get("http://www.myurl.com", function (data) {
//All done!
});
});
You have 3 options:
Do an AJAX request to subscribe the user
$('#emailsubscribe').on('click', function () {
$.get('/email-subscribe/' + USER_ID, function () {
// redirect goes here
window.location = 'REDIRECT_URL';
});
});
Use an iframe and when the iframe has loaded close the iframe (ugly, hacky, not recommended)
Have the subscribe page redirect the user back. Aka do the common messages of "You have been subscribed. Redirecting back in 5seconds...". You would need to pass the redirect link to the subscribe page, aka
window.location = '/subscribe/USER_ID?redirect_to=/my-redirect-page'
You need to refer the var, instead of typing another string to redirect.
//Html
<a id="subscription" href="http://example.com">Subscribe</a>
// Jquery
$("#emailsubscribe").click(function(e){
e.preventDefault();//this will prevent the link trying to navigate to another page
//do the update
var href = "http://example.com";
//when update has finished, navigate to the other page
window.location = href; //<<<< change this.
});

How to make sure hashtag attach the ajax updated content?

I had created a pagination with ajax. When user click the page number, it called the ajax function. I want to remember the previous ajax html data when user hit the back button. Therefore, I am trying to add the hash to each page. eg. when user click page 3, url is www.site.com/#3, page 4, is www.site.com/#4. It works OK so far. However, when I click the back button, it always load the second last page no matter the hash is 3 or 4. So, how can I make sure each hash attach to the ajax's update content? if the url is www.site.com/#4, it will always load the page 4 content. Appreicate.
$('#pagination a').click(function(e){
e.preventDefault();
$this = $(this).attr('href');//href is the page number
var data = {
action: 'post_pagination_ajax',
post_num : $this,
};
$.ajax({
url: ajax_front_gallery.ajaxurl,
type:'POST',
data: data,
success: function(data){
$('.post-content').html(data);
}
});
window.location.hash = $this;
return false;
});
You have a click event, however when you hit back button there is no any click event, browser just loads previous page from history. So what you have to do is to make also a load event. Final result will look something like this:
function loadContent ( url,data ) {
$.ajax({
url: url,
type:'POST',
data: data,
success: function(data){
$('.post-content').html(data);
}
});
}
$('#pagination a').click(function(e){
e.preventDefault();
var hash = $(this).attr('href');
var data = {
action: 'post_pagination_ajax',
post_num : $(this).attr('href')
};
loadContent( ajax_front_gallery.ajaxurl,data );
window.location.hash = hash;
return false;
});
$( window ).load(function() {
var data = {
action: 'post_pagination_ajax',
post_num : window.location.hash
};
loadContent( ajax_front_gallery.ajaxurl,data );
});
Edit:
Even though this solves your problem i would recommend doing it other way. Since you change hash and want to load content based on hash. There is a hashchange event for that. So you could do:
$(window).hashchange( function(){
var data = {
action: 'post_pagination_ajax',
post_num : location.hash
};
loadContent( ajax_front_gallery.ajaxurl,data );
});
//Trigger hash-change if page laoded with existing hash
$(window).hashchange();
And you won't need any click event on a preventing the default behaviour, because default behaviour of changing hash in url is what you want.
So I am not really sure if there is a standard how browser handle the url fragment (hash). The problem is that setting the hash is originally used for saying the browser where to scroll (with anchors etc.: http://www.w3schools.com/jsref/prop_loc_hash.asp). So when you set the hash most browser will put a new state in the history but will not use the current state of the DOM but use the old one before the hash was set.
But I can say, when ever I implement asynchrone paging with Javascript I do it similiar like you do, but I check the hash on the page load and load the specific page, so you always have the result you want.
I think this is the way the Google search works and it was the source of my idea.

Javascript function that executes when leaving page without prompting user

I'm looking for a javascript function that executes when the user leaves the page, similar to the onbeforeunload function, but I don't want the user notified with a dialog box
This performs an action but doesn't show a dialog box.
window.onbeforeunload = function(){
console.log('something');
}
As David wrote, sending data to the server doesn't reliably work. However, you can attach an event handler to all links, prevent the default action, wait for the server response and then trigger the user's indented navigation. This is how Piwik and other statistics tools collect information.
For instance:
<script>
$('a').click(function() {
var my_href = $(this).attr('href');
$.ajax({url: 'http://some-url-here', success:function() {
location.href=my_href; // navigate now
}});
return false; // stop default navigation action
});
</script>
This is of course not triggered when the user just closes the tab, fills a form, types a new address etc.

Check for page refresh or close with jQuery/javascript

I am looking to check if a page has been refreshed or closed with jQuery or javascript.
What I have currently is I have some database values that I want to delete if the user either navigates away or refreshes the page.
I am using AJAX calls to delete the values.
Right now, I have the following code:
The handler:
window.beforeunload = cleanUp;
The cleanUp() method:
function cleanUp() {
// Check to see if it's an actual page change.
if(myActualLeave) {
$.ajax({
type: "POST",
url: "/api/cleanup",
data: { id: myLocalId },
success: function (data) {
console.log(myLocalId + " got removed from the database.");
}
});
}
// Reset the flag, so it can be checked again.
myActualLeave = true;
}
Where myActualLeave is a flag that I set to false when AJAX calls are made, so they don't trigger the beforeunload handler.
The problem I am running into is that when I click a link on my page, so for instance a link to Google, the window.beforeunload doesn't trigger. I may have a misunderstanding of this, but I have tried using jQuery's $(window).unload(...); and the onbeforeunload trigger as well.
What should I use to call javascript when:
the user refreshes the page,
when the user navigates away from the page, or
when the user closes the page?
Edit: It came up in a comment that I could use a click() jQuery handler to detect navigating away. I should have made it more specific that I don't mean when the user clicks a link only then I want it to proc. I want it to trigger when they change pages in any way. So if the address bar gets typed in, for instance.
You should try "onbeforeunload" :
window.onbeforeunload
But i think you can't put "active" (ajax call) code in this callback function. All you can do is defining a confirm modal window that will be displayed to the user before leaving like :
Are you sure you want to leave because...
So you should do as #Leeish said : put a code in the .on('click') of the link so it can launch the ajax call before sending to another page.
But for the "refresh" or "close" scenario, you can consider marking your database row as "draft" (or whatever) and if not saved when on the next page, delete the draft line.

How to handle every link click on a page in JS or jQuery?

People create their own websites using WYSIWYG creator i give them. These websites have links inside of them. Also they can explore the HTML of the website and put there their own links.
I would like now to handle every link click occurring in website created with my creator and log it to my server. I know how to pass the data from JS or jQuery to PHP server. But what i need to know is how to handle the moment when person clicks a link, postpone the redirection for some moment, and in this time get the url and title of this link and send to my PHP server.
So how to handle every link click (or location change) on website that structure i don't know and get the link and title of the link clicked?
$('a').click(function(e) {
e.preventDefault();
var href = $(this).attr('href');
var title = $(this).attr('title');
// Send your data to php
if ($(this).attr('target') === '_blank') {
window.location.href = href; // redirect to href
} else {
window.open(href);
}
});
jQuery("a").click(function(){
var href = $(this).attr('href');
$.post('/', {link: href}).then(function(){ document.location = href; });
return false;
});
just a try
To intercept every link, just place this function somewhere that every page has access to (header/footer/etc.):
$('a').click(function(event) {
event.preventDefault();//To prevent following the link
//Your logic. attr('href') and attr('title')
});
You can use jQuery to do this. Use the on event and bind to the click event of a element. You can then do an event.preventDefault(); do your logic and then continue as normal by getting the href from the target.
Why you want to wait till logging is completed for the redirection. Let it be an asynchronous call so that user don't need to wait. If you want to have your server page in a different domain, to tackle the cross domain ajax issue, use jsonp datatype.
$('a').click(function() {
$.ajax({
url:"yourwebsite/loggingpage.php?data="+$(this).attr("href"),
dataType: 'jsonp' // Notice! JSONP <-- P (lowercase)
});
});
and in loggingpage.php, you can read the request data and log it to your persistent storage or wherever you want.

Categories

Resources