I am implementing my own Like/Unlike system for my website. The PHP part is already done and all working, but I'm trying to make the Like/Unlike process all asynchronous with jQuery's AJAX methods.
What I'm trying to achieve is let an user press the like button and then the like button will become yellow (like being pressed) and the URL will change to unlike and when clicked, the user will basically unlike the item and the button will get its original color again.
The liking part is already working, but I'm failing to toggle between these two.
This is what I've been trying:
HTML/TWIG:
<li><span class="glyphicon glyphicon-thumbs-up" {% if S_IMAGE_LIKED == true %}style="color: #f0c36d;" title="Unlike"{% else %}title="Like"{% endif %} data-placement="right"></span></li>
jQuery:
$('[data-image-action="likeUnlike"]').click(function(e){
var likeHref = $(this).attr('href');
var likeUnlike = (likeHref.indexOf('unlike') != -1) ? 'unlike' : 'like';
var unLikeUrl = likeHref.replace(!likeUnlike, likeUnlike); // This is wrong, but how else do I do this?
var thumbColor = (likeUnlike == 'like') ? '#f0c36d' : '#eee';
$(this).attr('href', unLikeUrl);
$('.image-options .glyphicon-thumbs-up').attr('data-original-title', ucfirst(likeUnlike));
$('.image-options .tooltip-inner').text(ucfirst(likeUnlike));
$('.image-options .glyphicon-thumbs-up').css('color', thumbColor);
$.ajax({
type: 'GET',
url: likeHref,
success: function(data){
// console.log(data); return;
var response = $.parseJSON(data);
if ('error' in response)
{
display_alert(response.error, 'danger', 3000, 'top');
return;
}
$('.likeCount').text(response.likeCount);
}
});
e.preventDefault();
return false;
});
After refreshing the page, the logic works great enough with the Twig if statements, but I want to achieve the same without having to reload the page.
So again in summary:
User clicks Like
Glyphicon turns yellow, title changes to Unlike and URL changes to unlike
User now clicks Unlike
Glyphicon turns light greyish, title changes to Like and URL changes to like
How can I achieve this? What's wrong in my code?
// This is wrong, but how else do I do this?
likeHref.replace(!likeUnlike, likeUnlike);
Basically you want to replace the current state with its reverse (which is not what the boolean NOT does for us :-) ). The current is likeUnlike, so do
var unlikeLike = (likeUnlike == 'like') ? 'unlike' : 'like';
Now, since replace does take a regular expression, we can simply match both possible wordings and replace them with the new:
var unlikeHref = likeHref.replace(/(un)?like/g, unlikeLike);
There's a lot happening in your code. Try to isolate the bits and pieces.
Firstly, your problem does not seem to have anything to do with the ajax request, unless that's throwing an exception for some reason. Changing the link url and the icon style when a user clicks on it should be simple though.
My suggestion on how proceed in debugging, step by step:
Check the browser console (eg. firebug) for any js exceptions
Ignore the ajax request and just focus on toggling the link url and icons style in the click event.
Check the value of the href attribute and all the other variables that are being set.
What is returning ucfirst, upper case first string?
Also, you will want to prevent the user clicking on the like/unlike link while the ajax request is in progress.
I hope I could help with this.
Related
I'm sort of new to JQuery, but I'm practicing everyday. My goal is to open the link after the buttons have been clicked but the link doesn't seem to be opening. I'm trying to open the link inside the if statement so everything happens accordingly.
window.setInterval(function(){
if ($('#add-remove-buttons').find('.button').length > 0) {
$('#size').val($('#size option').filter(function(ind, el) {
return $(el).text() === 'Large';
}).val());
$('#add-remove-buttons').find('.button').trigger('click');
setTimeout(function() {
window.location.replace('http://myweblink');
}, 900);
}
}, 100);
EDIT (STILL NEED HELP)
I've tried changing it but it doesn't load. I think it might be getting stuck in the 100ms loop. I put the function in a 100ms loop so it can detect if ($('#add-remove-buttons').find('.button').length > 0) I also just realized that after the user clicks the button, this html automatically appears:
<fieldset id="add-remove-buttons"><input class="button remove" name="commit" value="remove" type="submit">keep shopping</fieldset>
This means that the if statement : if ($('#add-remove-buttons').find('.button').length > 0) from my code, becomes false and the code for changing the URL doesn't run. Is there a way to detect the presence of the html code above like the if statement that became false? After I figure that out, I can put the window.location.href = "http://myweblink"; and then get it to work!
And in your code it is missing the complete web address.
Use
window.location.replace('http://myweblink.com');
Instead
window.location.replace('http://myweblink');
To redirect,jQuery is not necessary, and window.location.replace(...) will best simulate an HTTP redirect.
It is better than using window.location.href =, because replace() does not keep the originating page in the session history, meaning the user won't get stuck in a never-ending back-button fiasco. If you want to simulate someone clicking on a link, use location.href. If you want to simulate an HTTP redirect, use location.replace.
For example:
// similar behavior as an HTTP redirect
window.location.replace("http://stackoverflow.com");
// similar behavior as clicking on a link
window.location.href = "http://stackoverflow.com";
You can read the answer here.
Try
window.location.href = "http://your.wesite.com";
This will replace your address bar.
If you're using jQuery, just use $(location).attr('href',url);.
window.location.href seems to have inconstant behavior in some browsers, in fact, it flat out doesn't work in my version of Firefox.
Is there any way to use JavaScript's OnUnload() function to find out which URL the user is navigating away to?
For example, if my code is in page1.html, and the user clicks a link to http://example.com, is there any way for JavaScript code present in page1.html, to retrieve the URL "http://example.com" and display/store it before the page unloads?
I am able to do this if I invoke a function through my link by using its OnClick, but I cannot find a way to do this otherwise. (I can post my code for that if needed, but it does meet my business requirement)
EDIT : This looks to be impossible, since my business requirement demands that I do not make any change to the content of the page, excepting the adding in of a javascript file where this code is present.
Ignore onBeforeUnload/onUnload, you don't need that. You can do it with a simple click handler like this:
$('a').on('click', function(e)
{
e.preventDefault();
var destinationLink = $(this).attr('href');
$.post('/your/analytics/url', {link:destinationLink}, function()
{
// Success
window.location.href = destinationLink;
});
});
This will stop any link from working until it's been submitted to your analytics so it's not ideal - you need to make sure what ever is receiving the data does so as quickly as possible.
You could replace the current url of the clicked link.
That will allow you to call your server to do the check of the clicked url, and then redirect it.
The code bellow change the url of the clicked link only for a couple of microseconds
$("a").on("click",function(e){
// Save the current link
var h = this.href;
//Change the link of the current a
this.href = "http://www.example1.com/redirect.php?url="+encodeURI(h);
// replace the href with the original value on the next stack
setTimeout((function(my_link){
return function(){
my_link.href = h;
};
})(this),0);
});
my link
So I want to be able to have a different styling for a link after you go to the page it's clicked on. I have been using the following code:
$(document).ready(function(){
var url = document.URL;
function contains(search, find) {
return search.indexOf(find) !== -1;
};
$('#topbar a').each(function(){
var link = $(this).attr('href');
var answer = contains(link,url);
if(answer === true){
$(this).addClass('check');
}
else{
$(this).addClass('nocheck');
};
});
});
This goes through the links in my navigation bar and checks if it's on the same page as the link, and it works, but I can't use it in one specific case: Random.
I have a link that generates a random page from the pages I have, so it does not have a specified link as it links to a function to randomly generate the page (note: I cannot change the function or access information from it).
So how can I detect that the random link was clicked previously so i can give it the .check class
If i understand your question correctly, your function does not work for the randomlink because this has a href like http://mysite.com/random, but the server will actualy redirect you to a different page, like http://mysite.com/about-me, and therefore the url of the active page does not match the href of the random button, and it will not get the active state.
One could argue if you would want it to get the active state, cause clicking it again would not (likely) bring you to the same page, but that is besides the question.
I can see to ways to solve this.
server side:
In stead of redirecting to ie. http://mysite.com/about-me in the random function, you could also redirect to http://mysite.com/about-me?random. By adding this get variable, you should not change the behaviour of the link (unless you have some very strict controller, or that variable is actually used, but that is unlikely). You could then detect with javascript if that variable is present in the url, and then activate the random button.
Something like this:
$(document).ready(function(){
var url = document.URL;
// check for random
if (url.indexOf('?random') >= 0) {
$('#topbar a.random').addClass('check');
}
// check all other
$('#topbar a:not(.random)').each(function(){
if($(this).attr('href').indexOf(url) >= 0){
$(this).addClass('check');
}
else{
$(this).addClass('nocheck');
};
});
});
cookie:
If you do not have acces to the server side random controller, you could do it entirely with javascript, by the use of a cookie (the only way I know to make a variable persist trough page requests).
On click of the random button, you would first set a random cookie to true with javascript, before letting the actual link do it's thing. On entering the page, you could then do a similar check as in my previous option, but in stead of the url you check if the cookie is tre. If so, you change it to false (so on the next page request the random button will not be active again) and set the randombutton to active.
As I believe the first solution is to be preferred (cookies should only be used as a last resort, they are sent on every page request, which means extra data, and your user might have cookies disabled, or there might be laws against using cookies, so the function could not always work), I will not write the javascript yet. Feel free to ask if you prefer this solution and need further help however.
I'm in the SeleniumIDE , but calling out to javascript.
Seems like this would be a fairly common scenario for others too.
I have a good test suite but the first thing it does is login.
I would like the suite to start off be making sure I am logged out and if not, logging me out.
I can tell if I am logged in by the presence of a 'Logout' hyperlink
But I only want to click on logout IF I am currently logged in, otherwise I want to do nothing, as trying to click on a non-existent element would raise an error if I am not already logged in)
So logically this is:
if ui element(logout link in my case) exists
click on logout link
else
do nothing
end
I am using the Selenium IDE and calling javascript - Given that I can't do if then in the basic seleniumIDE I was hoping I could do this in javascript itself.
something like:
store javascript{if ([a with text 'Logout' exists]) then click on it end;} id1
although instead of click on it [this], it would also be ok (though more brittle) if I just visited the url which is
http://my-apps-domain/users/sign_out
but I'm not sure of the exact syntax.
The relevant HTML is:
<li>Logout</li>
If it exists I would like to click on the a (or visit the url directly), otherwise nothing.
I would like to find a non-jquery solution if possible.
Update: I have found that even javascript{window.location.replace('http://google.com') } closes my seleniumIDE window and replaces it with google but doesn't affect the actual window where the tests themselves were running.
Triggering a click event in raw JavaScript can be tricky (check out this answer: https://stackoverflow.com/a/10339248/2386700)
However, if you can also use jQuery, that would simplify things. For example, if the logout button has an id like "logout" then you could do something like this:
var logoutButton = $('#logout');
if (logoutButton != null) {
logoutButton.click();
}
Since you don't have control over the HTML, I suggest referencing the link in another manner. The URL seems very reliable for that purpose:
var logoutLink = document.querySelector('a[href="/users/sign_out"]');
if(logoutLink != null) {
window.location.href = logoutLink.href;
}
You don't need to fire any kind of click event, because page navigation can easily be done with window.location.
UPDATE:
Another idea is to assign your button an id, then click it with selenium:
var logoutLink = document.querySelector('a[href="/users/sign_out"]');
if(logoutLink != null) {
logoutLink.setAttribute("id", "logoutLink");
}
I have a handler for onbeforeunload
window.onbeforeunload = unloadMess;
function unloadMess(){
var conf = confirm("Wait! Before you go, please share your stories or experiences on the message forum.");
if(conf){
window.location.href = "http://www.domain.com/message-forum";
}
}
but I'm not sure how to know if the url they clicked on the page is within the site.
I just want them to alert them if they will leave the site.
It's not possible to do this 100% reliably, but if you detect when the user has clicked on a link on your page, you could use that as a mostly-correct signal. Something like this:
window.localLinkClicked = false;
$("a").live("click", function() {
var url = $(this).attr("href");
// check if the link is relative or to your domain
if (! /^https?:\/\/./.test(url) || /https?:\/\/yourdomain\.com/.test(url)) {
window.localLinkClicked = true;
}
});
window.onbeforeunload = function() {
if (window.localLinkClicked) {
// do stuff
} else {
// don't
}
}
I've got one idea, but I don't know if it's work. My suggestion is, add each link an onClick event with a function call. That function reads just the href attribute and store into a variable with global scope.
var clickedHrefAttrValue = "";
function getClickUrl(currentLink)
{
clickedHrefAttrValue = $(currentLink).attr("href");
return true;
}
The html for the a tags must be looks like following:
Linktext
and in your given function:
function getClickUrl()
{
if (clickedHrefAttrValue.indexOf("<your condition>" > -1)
{
//what ever you want do to
}
}
It is just an idea, but I think it is worth to try it.
If you are having issues because your website may have both absolute and relative local links, I have another solution (using jQuery):
Demo
/* EXTERNAL LINK WARNING
=========================================*/
$('a').on('click', function(e){
e.preventDefault();
var url = $(this).attr('href'),
host = location.host;
if (url.indexOf(host) > -1 || url.indexOf('http','https') == -1){
/* If we find the host name within the URL,
OR if we do not find http or https,
meaning it is a relative internal link
*/
window.location.href = url;
} else {
var warn = confirm('You\'re leaving the domain.\n\nAre you sure?');
if(warn == true) {
window.location.href = url,'_blank';
} else {
e.preventDefault;
}
}
});
So I needed to do this so I could log a user out if they left the site from any page, but not if they navigate within the site. Here is my solution using JS and PHP
On every page where they need to remain logged in, set a session variable:
<?php
session_start();
$_SESSION["isInSession"] = true;
?>
Now create two scripts:
clear-in-session.php
<?php
session_start();
unset($_SESSION["isInSession"]);
?>
logout.php
<?php
session_start();
if(isset($_SESSION["isInSession"]) exit();
//do logout code here
?>
Now we set 2 events in JS:
window.addEventListener('beforeunload', function(event) {
$.ajax({
type: 'POST',
async: false,
url: 'clear-in-session.php'
});
});
window.addEventListener('unload', function(event) {
$.ajax({
type: 'POST',
async: false,
url: 'logout.php'
});
});
To explain the order of events when the user navigates to another page in the same site:
The user navigates away
beforeunload is triggered, calling clear-in-session.php which removes the isInSession variable
The new page is loaded, setting isInSession to true
unload is triggered, calling logout.php, but because isInSession has been set back to true, the logout code is never called
When the user navigates to a page outside of the site (or to any page on the site that doesn't set isInSession):
The user navigates away
beforeunload is triggered, calling clear-in-session.php which removes the isInSession variable
The new page is loaded
unload is triggered, calling logout.php, isInSession has been deleted, so the logout code is called
Sorry for necro but this thread still comes up when searching for the answer to this question
Note: This answer uses jQuery for post calls to the php. It is entirely possible to do this in pure JS, but it was easier to illustrate in jQuery
There is a good solution to this which I implemented in my website recently. Just imagine this, everything thats going to be in your website that navigates the user is either going to be a link (anchor tag), button, clickable image or something on these lines. Its definitely not going to be the body element.
Now what happens when a user leaves the website, he/she can either type in a url and press enter, click a bookmark or press the back/forward buttons.
When a user does do that, do this:
$(window).on('beforeunload', function(e)){
if(e.target.activeElement.nodeName.toLowerCase() == 'body'){
yourFunction();
});
What happens is that the body becomes the active element in the target in these cases (when user leaves the website) and this is not the case when the user clicks on internal website navigable elements.
This is a clean, easy solution. Let me know if you face any issues.